├── .gitignore ├── public ├── assets │ ├── img │ │ ├── avatar.png │ │ ├── stream.gif │ │ ├── link.svg │ │ ├── back.svg │ │ ├── twitch.svg │ │ ├── exit.svg │ │ ├── facebook.svg │ │ ├── in.svg │ │ ├── instagram.svg │ │ ├── edit.svg │ │ ├── youtube.svg │ │ ├── twitter.svg │ │ ├── logout.svg │ │ ├── github.svg │ │ └── qris.svg │ ├── notif │ │ ├── ping.mp3 │ │ └── notif.mp3 │ └── js │ │ ├── swal_overlay_test.js │ │ ├── custom.js │ │ ├── settings.js │ │ ├── pagination.js │ │ ├── swal_donate.js │ │ ├── jquery.marquee.min.js │ │ └── anime.min.js ├── index.php └── .htaccess ├── core ├── Filter │ ├── Auth.php │ └── CSRF.php ├── Views │ ├── auth │ │ ├── layout.kyaaaa.php │ │ └── auth.kyaaaa.php │ ├── streamoverlay │ │ ├── donatenotification │ │ │ ├── index.kyaaaa.php │ │ │ └── layout.kyaaaa.php │ │ └── runningtext │ │ │ ├── index.kyaaaa.php │ │ │ └── layout.kyaaaa.php │ ├── admin │ │ ├── layout.kyaaaa.php │ │ ├── settings │ │ │ ├── layout.kyaaaa.php │ │ │ └── index.kyaaaa.php │ │ └── index.kyaaaa.php │ ├── donate │ │ ├── layout.kyaaaa.php │ │ └── index.kyaaaa.php │ └── invoice │ │ ├── layout.kyaaaa.php │ │ └── index.kyaaaa.php ├── Conf │ ├── Kyaaaa │ │ ├── Handler │ │ │ ├── Exception │ │ │ │ ├── ErrorException.php │ │ │ │ ├── Formatter.php │ │ │ │ ├── FrameCollection.php │ │ │ │ ├── Frame.php │ │ │ │ └── Inspector.php │ │ │ ├── Util │ │ │ │ ├── HtmlDumperOutput.php │ │ │ │ ├── Misc.php │ │ │ │ └── SystemFacade.php │ │ │ ├── Handler │ │ │ │ ├── HandlerInterface.php │ │ │ │ ├── CallbackHandler.php │ │ │ │ ├── Handler.php │ │ │ │ ├── JsonResponseHandler.php │ │ │ │ └── PlainTextHandler.php │ │ │ ├── Resources │ │ │ │ ├── views │ │ │ │ │ └── kyaaaa_prod.html.php │ │ │ │ ├── css │ │ │ │ │ └── prism.css │ │ │ │ └── js │ │ │ │ │ └── clipboard.min.js │ │ │ └── RunInterface.php │ │ ├── Renderer.php │ │ ├── CSRF.php │ │ ├── Session.php │ │ ├── Connection.php │ │ ├── Route.php │ │ ├── Router.php │ │ └── Request.php │ ├── Email.php │ ├── Database.php │ ├── App.php │ └── Routes.php ├── Models │ ├── DonateModel.php │ ├── PaymentModel.php │ └── AdminModel.php └── Controllers │ ├── DonateCtrl.php │ ├── PaymentCtrl.php │ └── AdminCtrl.php ├── composer.json ├── kyaaaa ├── LICENSE ├── README.md └── donateapp_db.sql /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /vendor/ 3 | composer.lock 4 | .gitattributes -------------------------------------------------------------------------------- /public/assets/img/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nauxxyzn/kyaaaa-donate-app/HEAD/public/assets/img/avatar.png -------------------------------------------------------------------------------- /public/assets/img/stream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nauxxyzn/kyaaaa-donate-app/HEAD/public/assets/img/stream.gif -------------------------------------------------------------------------------- /public/assets/notif/ping.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nauxxyzn/kyaaaa-donate-app/HEAD/public/assets/notif/ping.mp3 -------------------------------------------------------------------------------- /public/assets/notif/notif.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nauxxyzn/kyaaaa-donate-app/HEAD/public/assets/notif/notif.mp3 -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | kyaaaaRun(); -------------------------------------------------------------------------------- /public/assets/img/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Filter/Auth.php: -------------------------------------------------------------------------------- 1 | session = session(); 7 | } 8 | 9 | public function admin() { 10 | if (!$this->session->has('isAdmin')) { 11 | redirectTo(url('login')); 12 | } 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /public/assets/img/back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/auth/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= $title; ?> 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /core/Views/streamoverlay/donatenotification/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Thank You!

4 |

5 | Rp 1.000.000.000 dari Robot
6 | Ini adalah test, notifikasi donasi siap digunakan! 7 |

8 |
-------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Exception/ErrorException.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Exception; 8 | 9 | use ErrorException as BaseErrorException; 10 | 11 | /** 12 | * Wraps ErrorException; mostly used for typing (at least now) 13 | * to easily cleanup the stack trace of redundant info. 14 | */ 15 | class ErrorException extends BaseErrorException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /public/assets/img/twitch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/admin/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= $title; ?> 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "naufkia/kyaaaa-donate-app", 3 | "description": "Personal donation system with Stream Overlay", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "naufkia" 8 | } 9 | ], 10 | "require": { 11 | "php": "^7.3|^8.0", 12 | "pusher/pusher-php-server": "^7.1@beta" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Core\\": ["core/"] 17 | } 18 | }, 19 | "minimum-stability": "dev" 20 | } 21 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Disable directory browsing 2 | Options All -Indexes 3 | 4 | # ---------------------------------------------------------------------- 5 | # Rewrite engine 6 | # ---------------------------------------------------------------------- 7 | 8 | 9 | RewriteEngine On 10 | 11 | RewriteCond %{REQUEST_FILENAME} !-f 12 | RewriteCond %{REQUEST_FILENAME} !-d 13 | RewriteRule ^(.*)$ index.php?/$1 [L] 14 | 15 | 16 | # Force https 17 | # RewriteEngine On 18 | # RewriteCond %{HTTPS} off 19 | # RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] -------------------------------------------------------------------------------- /public/assets/img/exit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/img/facebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/admin/settings/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= $title; ?> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/assets/img/in.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/img/instagram.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Conf/Email.php: -------------------------------------------------------------------------------- 1 | 'smtp', 12 | 'SMTP_Host' => 'smtp.gmail.com', 13 | 'SMTP_Username' => 'email@gmail.com', 14 | 'SMTP_Password' => 'smtp_password_here', 15 | 'SMTP_Port' => 465, 16 | 'SMTP_Crypto' => 'ssl' 17 | ]; 18 | return new \Core\Conf\Kyaaaa\Mailer($config['SMTP_Host'], $config['SMTP_Port'], $config['SMTP_Crypto'], $config['SMTP_Username'], $config['SMTP_Password']); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/Views/donate/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= $title; ?> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/assets/img/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kyaaaa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | view = $view; 8 | $this->data = $data; 9 | } 10 | 11 | public function getView() { 12 | return $this->view; 13 | } 14 | 15 | public function getData() { 16 | return $this->data; 17 | } 18 | 19 | public function send() { 20 | $view = $this->getView(); 21 | $data = extract($this->getData()); 22 | ob_start(); 23 | include(viewPath($view, $data)); 24 | $content = ob_get_contents(); 25 | ob_end_clean(); 26 | require_once viewPath(dirname($view) . '/' . 'layout'); 27 | } 28 | } -------------------------------------------------------------------------------- /public/assets/img/youtube.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Models/DonateModel.php: -------------------------------------------------------------------------------- 1 | select('*'); 10 | $query = $builder->get()[0]; 11 | return $query; 12 | } 13 | 14 | public function get_donations() { 15 | $builder = DB::query('donations'); 16 | $builder->select('*'); 17 | $builder->where('status', 'PAID'); 18 | $builder->orderBy('id', 'DESC'); 19 | $query = $builder->get(); 20 | return $query; 21 | } 22 | 23 | public function get_settings() { 24 | $builder = DB::query('settings'); 25 | $builder->select('*'); 26 | $query = $builder->get()[0]; 27 | return $query; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Util/HtmlDumperOutput.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Util; 8 | 9 | /** 10 | * Used as output callable for Symfony\Component\VarDumper\Dumper\HtmlDumper::dump() 11 | * 12 | * @see TemplateHelper::dump() 13 | */ 14 | class HtmlDumperOutput 15 | { 16 | private $output; 17 | 18 | public function __invoke($line, $depth) 19 | { 20 | // A negative depth means "end of dump" 21 | if ($depth >= 0) { 22 | // Adds a two spaces indentation to the line 23 | $this->output .= str_repeat(' ', $depth) . $line . "\n"; 24 | } 25 | } 26 | 27 | public function getOutput() 28 | { 29 | return $this->output; 30 | } 31 | 32 | public function clear() 33 | { 34 | $this->output = null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/Views/streamoverlay/runningtext/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | customer_name])) { 6 | $grouped[((object) $subarr)->customer_name] += ((object) $subarr)->amount; 7 | continue; 8 | } 9 | $grouped[((object) $subarr)->customer_name] = ((object) $subarr)->amount; 10 | } 11 | arsort($grouped); 12 | foreach ($grouped as $key => $value) { 13 | echo '' . explode(" ", $key)[0] . ': ' . ' Rp ' . number_format($value,0,',','.') . ''; 14 | } ?> 15 | Scan or go to donate link: https://nauf.space/donate 16 | 17 |
-------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Handler/HandlerInterface.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Handler; 8 | 9 | use Core\Conf\Kyaaaa\Handler\Exception\Inspector; 10 | use Core\Conf\Kyaaaa\Handler\RunInterface; 11 | 12 | interface HandlerInterface 13 | { 14 | /** 15 | * @return int|null A handler may return nothing, or a Handler::HANDLE_* constant 16 | */ 17 | public function handle(); 18 | 19 | /** 20 | * @param RunInterface $run 21 | * @return void 22 | */ 23 | public function setRun(RunInterface $run); 24 | 25 | /** 26 | * @param \Throwable $exception 27 | * @return void 28 | */ 29 | public function setException($exception); 30 | 31 | /** 32 | * @param Inspector $inspector 33 | * @return void 34 | */ 35 | public function setInspector(Inspector $inspector); 36 | } 37 | -------------------------------------------------------------------------------- /core/Filter/CSRF.php: -------------------------------------------------------------------------------- 1 | isValidRequest()){ 6 | echo json_encode([ 7 | 'success' => false, 8 | 'invoice' => '', 9 | 'msg' => 'Invalid token: donation only accept from orign webform, not http clients'] 10 | ); 11 | die; 12 | } 13 | } 14 | 15 | public function auth() { 16 | if(!csrf()->isValidRequest()){ 17 | $session = session(); 18 | $session->flash('notif', 'invalid token'); 19 | redirectTo(url('login')); 20 | exit(); 21 | } 22 | } 23 | 24 | public function update() { 25 | if(!csrf()->isValidRequest()){ 26 | $session = session(); 27 | $session->flash('notif', 'invalid token'); 28 | redirectTo(url('dashboard/settings')); 29 | exit(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /core/Conf/Database.php: -------------------------------------------------------------------------------- 1 | 'mysql', 18 | 'host' => '127.0.0.1', 19 | 'database' => 'donateapp_db', 20 | 'username' => 'root', 21 | 'password' => '', 22 | 'port' => 3306, 23 | 'sqlite_path' => '' 24 | ]; 25 | return $config; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/assets/img/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Conf/App.php: -------------------------------------------------------------------------------- 1 | 'kyaaaa_session', 27 | 'cookie_lifetime' => 86400, // Seconds 28 | 'cookie_domain' => '', 29 | 'cookie_samesite' => '', 30 | 'cookie_path' => '/', 31 | 'cache_expire' => '180', 32 | 'cache_limiter' => 'nocache' 33 | ]); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/Controllers/DonateCtrl.php: -------------------------------------------------------------------------------- 1 | DonateModel = new DonateModel(); 8 | $this->request = request(); 9 | } 10 | 11 | public function index() { 12 | $getusers = $this->DonateModel->get_users(); 13 | $data['title'] = 'Dukung @' . $getusers->username; 14 | $data['username'] = $getusers->username; 15 | $data['users'] = $getusers; 16 | $data['donations'] = $this->DonateModel->get_donations(); 17 | return view('donate/index', $data); 18 | } 19 | 20 | public function donate_notification() { 21 | $data['settings'] = $this->DonateModel->get_settings(); 22 | return view('streamoverlay/donatenotification/index', $data); 23 | } 24 | 25 | public function running_text() { 26 | $get_donations = $this->DonateModel->get_donations(); 27 | $data['donations'] = json_decode(json_encode($get_donations), true); 28 | return view('streamoverlay/runningtext/index', $data); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /core/Models/PaymentModel.php: -------------------------------------------------------------------------------- 1 | insert($data); 10 | $query = $builder->save(); 11 | return $query; 12 | } 13 | 14 | public function get_merchant_ref($merchant_ref) { 15 | $builder = DB::query('donations'); 16 | $builder->select('*'); 17 | $builder->where('merchant_ref', $merchant_ref); 18 | $query = $builder->get(); 19 | return $query; 20 | } 21 | 22 | public function update_donation($merchant_ref, $status) { 23 | $builder = DB::query('donations'); 24 | $builder->update(['status' => $status]); 25 | $builder->where('merchant_ref', $merchant_ref); 26 | $query = $builder->save(); 27 | return $query; 28 | } 29 | 30 | public function get_settings() { 31 | $builder = DB::query('settings'); 32 | $builder->select('*'); 33 | $query = $builder->get()[0]; 34 | return $query; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Naufal Azkia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/assets/img/logout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Resources/views/kyaaaa_prod.html.php: -------------------------------------------------------------------------------- 1 | 43 |
44 |
45 |

Kyaaaa~ Something Went Wrong!

46 |
47 |
48 | -------------------------------------------------------------------------------- /public/assets/img/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/invoice/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | QRIS Payment 8 | 9 | 10 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /core/Views/invoice/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/auth/auth.kyaaaa.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/img/qris.svg: -------------------------------------------------------------------------------- 1 | QRIS -------------------------------------------------------------------------------- /core/Views/streamoverlay/runningtext/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Running Text 4 | 5 | 6 | 7 | 24 | 25 | 26 |
27 | 28 |
29 | 30 | 31 | 45 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Handler/CallbackHandler.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Handler; 8 | 9 | use InvalidArgumentException; 10 | 11 | /** 12 | * Wrapper for Closures passed as handlers. Can be used 13 | * directly, or will be instantiated automagically by Core\App\Kyaaaa\Handler\Run 14 | * if passed to Run::pushHandler 15 | */ 16 | class CallbackHandler extends Handler 17 | { 18 | /** 19 | * @var callable 20 | */ 21 | protected $callable; 22 | 23 | /** 24 | * @throws InvalidArgumentException If argument is not callable 25 | * @param callable $callable 26 | */ 27 | public function __construct($callable) 28 | { 29 | if (!is_callable($callable)) { 30 | throw new InvalidArgumentException( 31 | 'Argument to ' . __METHOD__ . ' must be valid callable' 32 | ); 33 | } 34 | 35 | $this->callable = $callable; 36 | } 37 | 38 | /** 39 | * @return int|null 40 | */ 41 | public function handle() 42 | { 43 | $exception = $this->getException(); 44 | $inspector = $this->getInspector(); 45 | $run = $this->getRun(); 46 | $callable = $this->callable; 47 | 48 | // invoke the callable directly, to get simpler stacktraces (in comparison to call_user_func). 49 | // this assumes that $callable is a properly typed php-callable, which we check in __construct(). 50 | return $callable($exception, $inspector, $run); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/CSRF.php: -------------------------------------------------------------------------------- 1 | Init(); 11 | } 12 | 13 | public function setExpiry($expiry){ 14 | $this->token_expiry=$expiry; 15 | } 16 | 17 | public function setTokenName($tokenname){ 18 | $this->field_name=$tokenname; 19 | } 20 | 21 | public function setTokenKey($key){ 22 | $this->token_key=$key; 23 | } 24 | 25 | public function isValidRequest(){ 26 | if (empty($_POST[$this->field_name]) || empty($_SESSION['csrf']['token'])) { 27 | return false; 28 | } 29 | if(!hash_equals($_POST[$this->field_name],$_SESSION['csrf']['token']) || $_SESSION['csrf']['expiry'] < time()){ 30 | return false; 31 | } else { 32 | return true; 33 | } 34 | } 35 | 36 | public function tokenField(){ 37 | $token=$this->field_name; 38 | $token_value=$_SESSION['csrf']['token']; 39 | $html=""; 40 | echo $html; 41 | } 42 | 43 | private function Init(){ 44 | if(array_key_exists('csrf',$_SESSION)){ 45 | if(empty($_SESSION['csrf']['token']) || $_SESSION['csrf']['expiry'] < time()){ 46 | $this->generateToken(); 47 | } 48 | } 49 | else { 50 | $this->generateToken(); 51 | } 52 | } 53 | 54 | protected function generateToken() { 55 | $token=hash_hmac('sha256',session_id().time(),$this->token_key); 56 | $token=substr($token,0,32); 57 | $_SESSION['csrf']=array( 58 | 'token' => $token , 59 | 'expiry' => time() + $this->token_expiry 60 | ); 61 | } 62 | } -------------------------------------------------------------------------------- /public/assets/js/swal_overlay_test.js: -------------------------------------------------------------------------------- 1 | function makePayment(url) { 2 | fetch(url, { 3 | method: 'POST', 4 | }).then((response) => response.json()) 5 | .then((data) => { 6 | if (data.success != true) { 7 | Swal.fire({ 8 | icon: 'warning', 9 | text: 'Failed', 10 | showConfirmButton: false, 11 | timer: 2000 12 | }) 13 | } else { 14 | Swal.fire('Ok, check the overlay!', '', 'success') 15 | } 16 | }); 17 | } 18 | 19 | function doOverlayTest(url) { 20 | Swal.fire({ 21 | icon:'question', 22 | title: 'Test Overlay Donation?', 23 | html: 'before you go, put this link
( '+ url +'donate_notification )
to your stream app or open in new tab on your browser', 24 | showCancelButton: false, 25 | confirmButtonText: 'Test Now', 26 | confirmButtonColor: '#3650c0', 27 | showDenyButton: true, 28 | denyButtonText: 'Cancel', 29 | reverseButtons: true, 30 | allowOutsideClick:false, 31 | customClass: { 32 | actions: 'my-actions', 33 | cancelButton: 'order-1 right-gap', 34 | confirmButton: 'order-2', 35 | denyButton: 'order-3', 36 | } 37 | }).then((result) => { 38 | if (result.isConfirmed) { 39 | makePayment(url + 'test_notification'); 40 | } else if (result.isDenied) { 41 | Swal.dismiss(); 42 | } 43 | }) 44 | 45 | } -------------------------------------------------------------------------------- /public/assets/js/custom.js: -------------------------------------------------------------------------------- 1 | 2 | const amountBtn = document.querySelectorAll(".denomination") 3 | for (var i = 0; i < amountBtn.length; i++) { 4 | amountBtn[i].addEventListener('click', function(e) { 5 | document.querySelector('.selected').removeAttribute("checked"); 6 | document.querySelector('.selected').classList.remove("selected"); 7 | document.querySelector(".denomination-other input").value = ''; 8 | document.querySelector(".denomination-other input").classList.remove("selected"); 9 | this.classList.add("selected"); 10 | this.setAttribute('checked', ''); 11 | document.querySelector("button").innerHTML = 'Donate Rp ' + document.querySelector('.selected input').value 12 | const amount = document.querySelector('.selected input').value.replace(/[^0-9]/g, ''); 13 | document.querySelector("#amount").value = amount; 14 | // document.querySelector("#custom_amount").value = document.querySelector('.selected input').value; 15 | }); 16 | } 17 | 18 | var amount = document.querySelector(".denomination-other input"); 19 | amount.addEventListener('focus', function (event) { 20 | document.querySelector('.selected').removeAttribute("checked"); 21 | document.querySelector('.selected').classList.remove("selected"); 22 | amount.classList.add("selected"); 23 | document.querySelector("#amount").value = ''; 24 | document.querySelector("button").innerHTML = 'Donate Rp '; 25 | }); 26 | 27 | amount.addEventListener('keyup', function (event) { 28 | var n = this.value.replace(/\D/g,''); 29 | var r = n.replace(/\B(?=(\d{3})+(?!\d))/g, "."); 30 | amount.value = r; 31 | document.querySelector("button").innerHTML = 'Donate Rp ' + r; 32 | var newvalue = r.replace(/[^0-9]/g, ''); 33 | document.querySelector("#amount").value = newvalue; 34 | }); -------------------------------------------------------------------------------- /public/assets/js/settings.js: -------------------------------------------------------------------------------- 1 | let fileInput = document.getElementById("file-upload-input"); 2 | let fileSelect = document.getElementsByClassName("file-upload-select")[0]; 3 | fileSelect.onclick = function() { 4 | fileInput.click(); 5 | } 6 | fileInput.onchange = function() { 7 | let filename = fileInput.files[0].name; 8 | let selectName = document.getElementsByClassName("file-select-name")[0]; 9 | selectName.innerText = filename; 10 | } 11 | 12 | let fileInput2 = document.getElementById("file-upload-input2"); 13 | let fileSelect2 = document.getElementsByClassName("file-upload-select2")[0]; 14 | fileSelect2.onclick = function() { 15 | fileInput2.click(); 16 | } 17 | fileInput2.onchange = function() { 18 | let filename2 = fileInput2.files[0].name; 19 | let selectName2 = document.getElementsByClassName("file-select-name2")[0]; 20 | selectName2.innerText = filename2; 21 | } 22 | 23 | function showProfile() { 24 | document.getElementById('profile').style.display = 'initial'; 25 | document.getElementById('stream').style.display = 'none'; 26 | document.getElementById('tripay').style.display = 'none'; 27 | document.getElementById('pusher').style.display = 'none'; 28 | } 29 | function showStream() { 30 | document.getElementById('profile').style.display = 'none'; 31 | document.getElementById('stream').style.display = 'initial'; 32 | document.getElementById('tripay').style.display = 'none'; 33 | document.getElementById('pusher').style.display = 'none'; 34 | } 35 | 36 | function showTripay() { 37 | document.getElementById('profile').style.display = 'none'; 38 | document.getElementById('stream').style.display = 'none'; 39 | document.getElementById('tripay').style.display = 'initial'; 40 | document.getElementById('pusher').style.display = 'none'; 41 | } 42 | 43 | function showPusher() { 44 | document.getElementById('profile').style.display = 'none'; 45 | document.getElementById('stream').style.display = 'none'; 46 | document.getElementById('tripay').style.display = 'none'; 47 | document.getElementById('pusher').style.display = 'initial'; 48 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Kyaaaa-Donate-APP 2 | #### Personal donation system with Stream Overlay 3 | 4 | ![mimum_requirements_php](https://img.shields.io/badge/PHP-^7.4|^8.0-green?style=flat-square&logo=PHP) 5 | ![last_commit](https://img.shields.io/github/last-commit/naufkia/kyaaaa-php?style=flat-square) 6 | 7 | Kyaaaa-Donate-APP adalah sistem donasi pribadi dengan dukungan stream overlay.\ 8 | Project ini dibuat menggunakan framework php buatan sendiri ([Kyaaaa-PHP Framework](https://github.com/naufkia/kyaaaa-php)) 9 | 10 | ### What inside? 11 | 12 | * This project less than 5MB ✨ 13 | * [Kyaaaa-PHP Framework](https://github.com/naufkia/kyaaaa-php) - Lightweight PHP Framework 14 | * [Sweetalert2](https://sweetalert2.github.io/) - Replacement for javascript popup boxes 15 | * [Pusher WebSocket](https://pusher.com/channels) - Realtime features to your apps. 16 | 1) Pusher WebSocket digunakan untuk menerima data realtime donasi & pembayaran (invoice) 17 | * [Payment Gateway](https://tripay.co.id) - Payment Gateway 18 | * Pure css & vanilla js 19 | 20 | ### Fitur 21 | 22 | * QRIS Payment (hanya mendukung qris payment) 23 | * Stream Overlay : 24 | 1) Donate Notification : with Text-to-Speech, gif, and custom notification sound. 25 | 2) Running Text Contributors 26 | * Social Media links 27 | * Contributors History 28 | 29 | ### Installation 30 | Berhubung ([Kyaaaa-PHP](https://github.com/naufkia/kyaaaa-php)) framework belum support database migration, jadi harus import database secara manual. 31 | 32 | 1. `composer create-project naufkia/kyaaaa-donate-app:dev-main` 33 | 2. create `donateapp_db` database 34 | 3. import `donateapp_db.sql` 35 | 4. run this php cli (commandline): `php kyaaaa` 36 | 5. Open `http://localhost:5555` on your browser. 37 | 38 | ### Demo 39 | * [https://sawer.nauf.space/](https://sawer.nauf.space/) 40 | 41 | ### Default Credential 42 | * Login link local `http://localhost:5555/login` or [https://sawer.nauf.space/login](https://sawer.nauf.space/login) 43 | * Email : `demo@demo.com` 44 | * Password : `demo` 45 | 46 | ### Buy me a coffe 47 | [!["Buy Me A Coffee"](https://nauf.space/orange_img.webp)](https://nauf.space/donate) 48 | -------------------------------------------------------------------------------- /core/Models/AdminModel.php: -------------------------------------------------------------------------------- 1 | select('*'); 10 | $builder->where('email', $email); 11 | $query = $builder->get(); 12 | return $query; 13 | } 14 | 15 | public function get_donations() { 16 | $builder = DB::query('donations'); 17 | $builder->select('*'); 18 | $builder->orderBy('id', 'DESC'); 19 | $query = $builder->get(); 20 | return $query; 21 | } 22 | 23 | public function get_users() { 24 | $builder = DB::query('users'); 25 | $builder->select('*'); 26 | $query = $builder->get()[0]; 27 | return $query; 28 | } 29 | 30 | public function get_settings() { 31 | $builder = DB::query('settings'); 32 | $builder->select('*'); 33 | $query = $builder->get()[0]; 34 | return $query; 35 | } 36 | 37 | public function update_profile($data) { 38 | $builder = DB::query('users'); 39 | $builder->update($data); 40 | $query = $builder->save(); 41 | return $query; 42 | } 43 | 44 | public function update_settings($data) { 45 | $builder = DB::query('settings'); 46 | $builder->update($data); 47 | $query = $builder->save(); 48 | return $query; 49 | } 50 | 51 | public function count_paid() { 52 | $builder = DB::query('donations'); 53 | $builder->select('COUNT(id) as total'); 54 | $builder->where('status', 'PAID'); 55 | $query = $builder->get()[0]->total; 56 | return $query; 57 | } 58 | 59 | public function count_all() { 60 | $builder = DB::query('donations'); 61 | $builder->select('COUNT(id) as total'); 62 | $query = $builder->get()[0]->total; 63 | return $query; 64 | } 65 | 66 | public function total_paid_donation() { 67 | $builder = DB::query('donations'); 68 | $builder->select('SUM(amount) as total'); 69 | $builder->where('status', 'PAID'); 70 | $query = $builder->get()[0]->total; 71 | return $query; 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Util/Misc.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Util; 8 | 9 | class Misc 10 | { 11 | /** 12 | * Can we at this point in time send HTTP headers? 13 | * 14 | * Currently this checks if we are even serving an HTTP request, 15 | * as opposed to running from a command line. 16 | * 17 | * If we are serving an HTTP request, we check if it's not too late. 18 | * 19 | * @return bool 20 | */ 21 | public static function canSendHeaders() 22 | { 23 | return isset($_SERVER["REQUEST_URI"]) && !headers_sent(); 24 | } 25 | 26 | public static function isAjaxRequest() 27 | { 28 | return ( 29 | !empty($_SERVER['HTTP_X_REQUESTED_WITH']) 30 | && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); 31 | } 32 | 33 | /** 34 | * Check, if possible, that this execution was triggered by a command line. 35 | * @return bool 36 | */ 37 | public static function isCommandLine() 38 | { 39 | return PHP_SAPI == 'cli'; 40 | } 41 | 42 | /** 43 | * Translate ErrorException code into the represented constant. 44 | * 45 | * @param int $error_code 46 | * @return string 47 | */ 48 | public static function translateErrorCode($error_code) 49 | { 50 | $constants = get_defined_constants(true); 51 | if (array_key_exists('Core', $constants)) { 52 | foreach ($constants['Core'] as $constant => $value) { 53 | if (substr($constant, 0, 2) == 'E_' && $value == $error_code) { 54 | return $constant; 55 | } 56 | } 57 | } 58 | return "E_UNKNOWN"; 59 | } 60 | 61 | /** 62 | * Determine if an error level is fatal (halts execution) 63 | * 64 | * @param int $level 65 | * @return bool 66 | */ 67 | public static function isLevelFatal($level) 68 | { 69 | $errors = E_ERROR; 70 | $errors |= E_PARSE; 71 | $errors |= E_CORE_ERROR; 72 | $errors |= E_CORE_WARNING; 73 | $errors |= E_COMPILE_ERROR; 74 | $errors |= E_COMPILE_WARNING; 75 | return ($level & $errors) > 0; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Handler/Handler.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Handler; 8 | 9 | use Core\Conf\Kyaaaa\Handler\Exception\Inspector; 10 | use Core\Conf\Kyaaaa\Handler\RunInterface; 11 | 12 | /** 13 | * Abstract implementation of a Handler. 14 | */ 15 | abstract class Handler implements HandlerInterface 16 | { 17 | /* 18 | Return constants that can be returned from Handler::handle 19 | to message the handler walker. 20 | */ 21 | const DONE = 0x10; // returning this is optional, only exists for 22 | // semantic purposes 23 | /** 24 | * The Handler has handled the Throwable in some way, and wishes to skip any other Handler. 25 | * Execution will continue. 26 | */ 27 | const LAST_HANDLER = 0x20; 28 | /** 29 | * The Handler has handled the Throwable in some way, and wishes to quit/stop execution 30 | */ 31 | const QUIT = 0x30; 32 | 33 | /** 34 | * @var RunInterface 35 | */ 36 | private $run; 37 | 38 | /** 39 | * @var Inspector $inspector 40 | */ 41 | private $inspector; 42 | 43 | /** 44 | * @var \Throwable $exception 45 | */ 46 | private $exception; 47 | 48 | /** 49 | * @param RunInterface $run 50 | */ 51 | public function setRun(RunInterface $run) 52 | { 53 | $this->run = $run; 54 | } 55 | 56 | /** 57 | * @return RunInterface 58 | */ 59 | protected function getRun() 60 | { 61 | return $this->run; 62 | } 63 | 64 | /** 65 | * @param Inspector $inspector 66 | */ 67 | public function setInspector(Inspector $inspector) 68 | { 69 | $this->inspector = $inspector; 70 | } 71 | 72 | /** 73 | * @return Inspector 74 | */ 75 | protected function getInspector() 76 | { 77 | return $this->inspector; 78 | } 79 | 80 | /** 81 | * @param \Throwable $exception 82 | */ 83 | public function setException($exception) 84 | { 85 | $this->exception = $exception; 86 | } 87 | 88 | /** 89 | * @return \Throwable 90 | */ 91 | protected function getException() 92 | { 93 | return $this->exception; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /public/assets/js/pagination.js: -------------------------------------------------------------------------------- 1 | const container = document.querySelector("#paginated-list"); 2 | const listItems = document.querySelectorAll(".page .contributors"); 3 | const nextBtn = document.querySelector("#next-button"); 4 | const prevBtn = document.querySelector("#prev-button"); 5 | const paginationNumbers = document.querySelector("#pagination-numbers"); 6 | const itemsInPage = 4; 7 | const pagesNumber = Math.ceil(listItems.length / itemsInPage); 8 | let currentPage = 1; 9 | 10 | function pagination() { 11 | container.innerHTML = ""; 12 | const start = (currentPage - 1) * itemsInPage; 13 | const end = start + itemsInPage; 14 | const dataToAdd = Array.from(listItems); 15 | 16 | dataToAdd.slice(start, end).forEach((el) => { 17 | container.append(el); 18 | }); 19 | } 20 | 21 | function createNumberBtn() { 22 | const btnArray = []; 23 | for (let i = 1; i <= pagesNumber; i++) { 24 | const btn = document.createElement("button"); 25 | btn.innerHTML = i; 26 | btn.classList.add("pagination-number"); 27 | // paginationNumbers.append(btn); 28 | btnArray.push(btn); 29 | btnArray[0].classList.add("active"); 30 | btn.addEventListener("click", () => { 31 | btnArray.forEach((btn) => { 32 | btn.classList.remove("active"); 33 | }); 34 | btn.classList.toggle("active"); 35 | currentPage = +btn.innerHTML; 36 | pagination(); 37 | }); 38 | nextBtn.addEventListener("click", () => { 39 | btnArray.forEach((btn) => { 40 | btn.classList.remove("active"); 41 | btnArray[currentPage - 1].classList.add("active"); 42 | }); 43 | }); 44 | prevBtn.addEventListener("click", () => { 45 | btnArray.forEach((btn) => { 46 | btn.classList.remove("active"); 47 | btnArray[currentPage - 1].classList.add("active"); 48 | }); 49 | }); 50 | } 51 | } 52 | 53 | nextBtn.addEventListener("click", () => { 54 | if (currentPage === pagesNumber) { 55 | return false; 56 | } 57 | currentPage += 1; 58 | pagination(); 59 | }); 60 | 61 | prevBtn.addEventListener("click", () => { 62 | if (currentPage === 1) { 63 | return false; 64 | } 65 | currentPage -= 1; 66 | pagination(); 67 | }); 68 | 69 | pagination(); 70 | createNumberBtn(); 71 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Handler/JsonResponseHandler.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Handler; 8 | 9 | use Core\Conf\Kyaaaa\Handler\Exception\Formatter; 10 | 11 | /** 12 | * Catches an exception and converts it to a JSON 13 | * response. Additionally can also return exception 14 | * frames for consumption by an API. 15 | */ 16 | class JsonResponseHandler extends Handler 17 | { 18 | /** 19 | * @var bool 20 | */ 21 | private $returnFrames = false; 22 | 23 | /** 24 | * @var bool 25 | */ 26 | private $jsonApi = false; 27 | 28 | /** 29 | * Returns errors[[]] instead of error[] to be in compliance with the json:api spec 30 | * @param bool $jsonApi Default is false 31 | * @return static 32 | */ 33 | public function setJsonApi($jsonApi = false) 34 | { 35 | $this->jsonApi = (bool) $jsonApi; 36 | return $this; 37 | } 38 | 39 | /** 40 | * @param bool|null $returnFrames 41 | * @return bool|static 42 | */ 43 | public function addTraceToOutput($returnFrames = null) 44 | { 45 | if (func_num_args() == 0) { 46 | return $this->returnFrames; 47 | } 48 | 49 | $this->returnFrames = (bool) $returnFrames; 50 | return $this; 51 | } 52 | 53 | /** 54 | * @return int 55 | */ 56 | public function handle() 57 | { 58 | if ($this->jsonApi === true) { 59 | $response = [ 60 | 'errors' => [ 61 | Formatter::formatExceptionAsDataArray( 62 | $this->getInspector(), 63 | $this->addTraceToOutput() 64 | ), 65 | ] 66 | ]; 67 | } else { 68 | $response = [ 69 | 'error' => Formatter::formatExceptionAsDataArray( 70 | $this->getInspector(), 71 | $this->addTraceToOutput() 72 | ), 73 | ]; 74 | } 75 | 76 | echo json_encode($response, defined('JSON_PARTIAL_OUTPUT_ON_ERROR') ? JSON_PARTIAL_OUTPUT_ON_ERROR : 0); 77 | 78 | return Handler::QUIT; 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function contentType() 85 | { 86 | return 'application/json'; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /core/Conf/Routes.php: -------------------------------------------------------------------------------- 1 | get('/', [\Core\Controllers\DonateCtrl::class,'index']); 10 | 11 | $router->get('/donate_notification', [\Core\Controllers\DonateCtrl::class,'donate_notification']); 12 | 13 | $router->get('/running_text', [\Core\Controllers\DonateCtrl::class,'running_text']); 14 | 15 | $router->post('/callback', [\Core\Controllers\PaymentCtrl::class,'callback']); 16 | 17 | $router->post('/do_donate', [\Core\Controllers\PaymentCtrl::class,'do_donate']) 18 | ->middleware('\Core\Filter\CSRF#donate'); 19 | 20 | $router->get('/inv/:id', [\Core\Controllers\PaymentCtrl::class,'invoice']); 21 | 22 | $router->get('/login', [\Core\Controllers\AdminCtrl::class,'login']); 23 | 24 | $router->get('/logout', [\Core\Controllers\AdminCtrl::class,'logout']); 25 | 26 | $router->post('/auth', [\Core\Controllers\AdminCtrl::class,'auth']) 27 | ->middleware('\Core\Filter\CSRF#auth'); 28 | 29 | $router->get('/dashboard', [\Core\Controllers\AdminCtrl::class,'index']) 30 | ->middleware('\Core\Filter\Auth#admin'); 31 | 32 | $router->get('/dashboard/settings', [\Core\Controllers\AdminCtrl::class,'settings']) 33 | ->middleware('\Core\Filter\Auth#admin'); 34 | 35 | $router->post('/test_notification', [\Core\Controllers\AdminCtrl::class,'test_notification']) 36 | ->middleware('\Core\Filter\Auth#admin'); 37 | 38 | $router->post('/update_profile', [\Core\Controllers\AdminCtrl::class,'update_profile']) 39 | ->middleware('\Core\Filter\Auth#admin') 40 | ->middleware('\Core\Filter\CSRF#update'); 41 | 42 | $router->post('/update_stream', [\Core\Controllers\AdminCtrl::class,'update_stream']) 43 | ->middleware('\Core\Filter\Auth#admin') 44 | ->middleware('\Core\Filter\CSRF#update'); 45 | 46 | $router->post('/update_tripay', [\Core\Controllers\AdminCtrl::class,'update_tripay']) 47 | ->middleware('\Core\Filter\Auth#admin') 48 | ->middleware('\Core\Filter\CSRF#update'); 49 | 50 | $router->post('/update_pusher', [\Core\Controllers\AdminCtrl::class,'update_pusher']) 51 | ->middleware('\Core\Filter\Auth#admin') 52 | ->middleware('\Core\Filter\CSRF#update'); 53 | 54 | $router->run(); 55 | } 56 | } -------------------------------------------------------------------------------- /core/Views/admin/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Exception/Formatter.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Exception; 8 | 9 | class Formatter 10 | { 11 | /** 12 | * Returns all basic information about the exception in a simple array 13 | * for further convertion to other languages 14 | * @param Inspector $inspector 15 | * @param bool $shouldAddTrace 16 | * @return array 17 | */ 18 | public static function formatExceptionAsDataArray(Inspector $inspector, $shouldAddTrace) 19 | { 20 | $exception = $inspector->getException(); 21 | $response = [ 22 | 'type' => get_class($exception), 23 | 'message' => $exception->getMessage(), 24 | 'code' => $exception->getCode(), 25 | 'file' => $exception->getFile(), 26 | 'line' => $exception->getLine(), 27 | ]; 28 | 29 | if ($shouldAddTrace) { 30 | $frames = $inspector->getFrames(); 31 | $frameData = []; 32 | 33 | foreach ($frames as $frame) { 34 | /** @var Frame $frame */ 35 | $frameData[] = [ 36 | 'file' => $frame->getFile(), 37 | 'line' => $frame->getLine(), 38 | 'function' => $frame->getFunction(), 39 | 'class' => $frame->getClass(), 40 | 'args' => $frame->getArgs(), 41 | ]; 42 | } 43 | 44 | $response['trace'] = $frameData; 45 | } 46 | 47 | return $response; 48 | } 49 | 50 | public static function formatExceptionPlain(Inspector $inspector) 51 | { 52 | $message = $inspector->getException()->getMessage(); 53 | $frames = $inspector->getFrames(); 54 | 55 | $plain = $inspector->getExceptionName(); 56 | $plain .= ' thrown with message "'; 57 | $plain .= $message; 58 | $plain .= '"'."\n\n"; 59 | 60 | $plain .= "Stacktrace:\n"; 61 | foreach ($frames as $i => $frame) { 62 | $plain .= "#". (count($frames) - $i - 1). " "; 63 | $plain .= $frame->getClass() ?: ''; 64 | $plain .= $frame->getClass() && $frame->getFunction() ? ":" : ""; 65 | $plain .= $frame->getFunction() ?: ''; 66 | $plain .= ' in '; 67 | $plain .= ($frame->getFile() ?: '<#unknown>'); 68 | $plain .= ':'; 69 | $plain .= (int) $frame->getLine(). "\n"; 70 | } 71 | 72 | return $plain; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/assets/js/swal_donate.js: -------------------------------------------------------------------------------- 1 | const donateBtn = document.getElementById('donateBtn') 2 | 3 | function validateEmail(mail) { 4 | return (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail)) 5 | } 6 | 7 | function makePayment(url, privacy = false) { 8 | const formData = document.getElementById('donate_form') 9 | const data = new FormData(formData); 10 | if (privacy == true) { 11 | data.append('private', 'yes') 12 | } else { 13 | data.append('private', 'no') 14 | } 15 | fetch(url, { 16 | method: 'POST', 17 | body: data 18 | }).then((response) => response.json()) 19 | .then((data) => { 20 | if (data.success != true) { 21 | Swal.fire({ 22 | icon: 'warning', 23 | text: data.msg, 24 | showConfirmButton: false, 25 | timer: 5000 26 | }) 27 | } else { 28 | location.href = data.invoice 29 | } 30 | }); 31 | } 32 | 33 | function doDonate(url) { 34 | const name = document.getElementById('name').value 35 | const email = document.getElementById('email').value 36 | const msgs = document.getElementById('msgs').value 37 | const donate_amount = document.getElementById('amount').value 38 | if (name == '' || email == '' || msgs == '' || donate_amount == '') { 39 | Swal.fire({ 40 | icon: 'warning', 41 | text: 'harap isi nama, email, pesan, dan jumlah dukungan!', 42 | showConfirmButton: false, 43 | timer: 2500 44 | }) 45 | } else if (!validateEmail(email)) { 46 | Swal.fire({ 47 | icon: 'warning', 48 | text: 'format email salah!', 49 | showConfirmButton: false, 50 | timer: 2500 51 | }) 52 | } else { 53 | Swal.fire({ 54 | icon:'question', 55 | title: 'Dukung sebagai anonim?', 56 | text: 'Nominal dukungan dan pesan akan disembunyikan.', 57 | showCancelButton: false, 58 | confirmButtonText: 'Tidak', 59 | confirmButtonColor: '#3650c0', 60 | denyButtonColor: '#3650c0', 61 | showDenyButton: true, 62 | denyButtonText: 'Ya', 63 | reverseButtons: true, 64 | allowOutsideClick:false, 65 | customClass: { 66 | actions: 'my-actions', 67 | cancelButton: 'order-1 right-gap', 68 | confirmButton: 'order-2', 69 | denyButton: 'order-3', 70 | } 71 | }).then((result) => { 72 | if (result.isConfirmed) { 73 | Swal.fire({ 74 | timer: 5000, 75 | timerProgressBar: true, 76 | didOpen: () => { 77 | Swal.showLoading() 78 | } 79 | }) 80 | makePayment(url); 81 | } else if (result.isDenied) { 82 | Swal.fire({ 83 | timer: 5000, 84 | timerProgressBar: true, 85 | didOpen: () => { 86 | Swal.showLoading() 87 | } 88 | }) 89 | makePayment(url, true); 90 | } 91 | }) 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Util/SystemFacade.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Util; 8 | 9 | class SystemFacade 10 | { 11 | /** 12 | * Turns on output buffering. 13 | * 14 | * @return bool 15 | */ 16 | public function startOutputBuffering() 17 | { 18 | return ob_start(); 19 | } 20 | 21 | /** 22 | * @param callable $handler 23 | * @param int $types 24 | * 25 | * @return callable|null 26 | */ 27 | public function setErrorHandler(callable $handler, $types = 'use-php-defaults') 28 | { 29 | // Since PHP 5.4 the constant E_ALL contains all errors (even E_STRICT) 30 | if ($types === 'use-php-defaults') { 31 | $types = E_ALL; 32 | } 33 | return set_error_handler($handler, $types); 34 | } 35 | 36 | /** 37 | * @param callable $handler 38 | * 39 | * @return callable|null 40 | */ 41 | public function setExceptionHandler(callable $handler) 42 | { 43 | return set_exception_handler($handler); 44 | } 45 | 46 | /** 47 | * @return void 48 | */ 49 | public function restoreExceptionHandler() 50 | { 51 | restore_exception_handler(); 52 | } 53 | 54 | /** 55 | * @return void 56 | */ 57 | public function restoreErrorHandler() 58 | { 59 | restore_error_handler(); 60 | } 61 | 62 | /** 63 | * @param callable $function 64 | * 65 | * @return void 66 | */ 67 | public function registerShutdownFunction(callable $function) 68 | { 69 | register_shutdown_function($function); 70 | } 71 | 72 | /** 73 | * @return string|false 74 | */ 75 | public function cleanOutputBuffer() 76 | { 77 | return ob_get_clean(); 78 | } 79 | 80 | /** 81 | * @return int 82 | */ 83 | public function getOutputBufferLevel() 84 | { 85 | return ob_get_level(); 86 | } 87 | 88 | /** 89 | * @return bool 90 | */ 91 | public function endOutputBuffering() 92 | { 93 | return ob_end_clean(); 94 | } 95 | 96 | /** 97 | * @return void 98 | */ 99 | public function flushOutputBuffer() 100 | { 101 | flush(); 102 | } 103 | 104 | /** 105 | * @return int 106 | */ 107 | public function getErrorReportingLevel() 108 | { 109 | return error_reporting(); 110 | } 111 | 112 | /** 113 | * @return array|null 114 | */ 115 | public function getLastError() 116 | { 117 | return error_get_last(); 118 | } 119 | 120 | /** 121 | * @param int $httpCode 122 | * 123 | * @return int 124 | */ 125 | public function setHttpResponseCode($httpCode) 126 | { 127 | if (!headers_sent()) { 128 | // Ensure that no 'location' header is present as otherwise this 129 | // will override the HTTP code being set here, and mask the 130 | // expected error page. 131 | header_remove('location'); 132 | } 133 | 134 | return http_response_code($httpCode); 135 | } 136 | 137 | /** 138 | * @param int $exitStatus 139 | */ 140 | public function stopExecution($exitStatus) 141 | { 142 | exit($exitStatus); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Session.php: -------------------------------------------------------------------------------- 1 | 'kyaaaa_session', 16 | 'cookie_lifetime' => 86400, // Seconds 17 | 'cookie_domain' => '', 18 | 'cookie_samesite' => '', 19 | 'cookie_path' => '/', 20 | 'cache_expire' => '180', 21 | 'cache_limiter' => 'nocache' 22 | ]; 23 | 24 | /** 25 | * Start session 26 | * 27 | * @param array $options Array of options (see above) 28 | * @return void 29 | */ 30 | public function config($options = []) 31 | { 32 | session_start(array_merge(self::$options, $options)); 33 | self::$session = &$_SESSION; 34 | } 35 | 36 | /** 37 | * Set value to session 38 | * 39 | * @param mixed $key 40 | * @param mixed $value 41 | * @return void 42 | */ 43 | public function set($key, $value = null) 44 | { 45 | if (is_array($key)) { 46 | foreach ($key as $key => $value) { 47 | self::$session[$key] = $value; 48 | } 49 | } else { 50 | self::$session[$key] = $value; 51 | } 52 | } 53 | 54 | /** 55 | * Set flash data 56 | * 57 | * @param mixed $key 58 | * @param mixed $value 59 | * @return void 60 | */ 61 | public function flash($key, $value = null) 62 | { 63 | if (is_array($key)) { 64 | foreach ($key as $key => $value) { 65 | self::$session[$key] = $value; 66 | } 67 | } else { 68 | self::$session[$key] = $value; 69 | } 70 | } 71 | 72 | /** 73 | * Get value from session by specific key 74 | * 75 | * @param mixed $key 76 | * @param mixed $default Default value if key not exists 77 | * @return mixed 78 | */ 79 | public function get($key, $default = null) 80 | { 81 | return self::has($key) ? self::$session[$key] : $default; 82 | } 83 | 84 | /** 85 | * Get value by specific key and remove this key from session 86 | * 87 | * @param mixed $key 88 | * @return mixed 89 | */ 90 | public function getFlash($key) 91 | { 92 | $value = self::get($key); 93 | self::remove($key); 94 | return $value; 95 | } 96 | 97 | /** 98 | * Check if a specific key exists 99 | * 100 | * @param mixed $key 101 | * @return boolean 102 | */ 103 | public function has($key) 104 | { 105 | return array_key_exists($key, self::$session); 106 | } 107 | 108 | /** 109 | * Remove specific key 110 | * 111 | * @param mixed $key 112 | * @return void 113 | */ 114 | public function remove($key) 115 | { 116 | unset(self::$session[$key]); 117 | } 118 | 119 | /** 120 | * Clear session 121 | * 122 | * @return void 123 | */ 124 | public function clear() 125 | { 126 | session_unset(); 127 | session_destroy(); 128 | } 129 | 130 | /** 131 | * Get and/or set the current session id 132 | * 133 | * @param string|null $id 134 | * @return string|false 135 | */ 136 | public function id($id = null) 137 | { 138 | return session_id($id); 139 | } 140 | 141 | /** 142 | * Update the current session id with a newly generated one 143 | * 144 | * @param boolean $deleteOldSession 145 | * @return void 146 | */ 147 | public function regenerate($deleteOldSession = false) 148 | { 149 | session_regenerate_id($deleteOldSession); 150 | } 151 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Connection.php: -------------------------------------------------------------------------------- 1 | driver = $getConfig->config()['driver']; 10 | $this->username = $getConfig->config()['username']; 11 | $this->password = $getConfig->config()['password']; 12 | $this->database = $getConfig->config()['database']; 13 | $this->host = $getConfig->config()['host']; 14 | $this->port = $getConfig->config()['port']; 15 | $this->sqlite_path = $getConfig->config()['sqlite_path']; 16 | $this->charset = 'utf8'; 17 | } 18 | /** 19 | * @var object $connect, Holds the PDO connection object 20 | */ 21 | private $connect = null; 22 | 23 | /** 24 | * @var array $options, PDO mysql configuration options 25 | */ 26 | private $options = [ 27 | \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8', 28 | ]; 29 | 30 | /** 31 | * @throws PDOException 32 | * @throws Exception 33 | */ 34 | public function PDO ($driver = null) 35 | { 36 | if ($driver !== null) { 37 | $this->driver = strtolower($driver); 38 | } 39 | 40 | try { 41 | 42 | if ($this->driver === 'mysql') { 43 | $this->connectMySQl(); 44 | } elseif ($this->driver === 'pgsql') { 45 | $this->connectPostgreSQl(); 46 | } elseif ($this->driver === 'sqlsrv') { 47 | $this->connectSQlServer(); 48 | } elseif ($this->driver === 'sqlite') { 49 | $this->connectSQlite(); 50 | } 51 | 52 | } catch(\PDOException $e) { 53 | $getConf = new \Core\Conf\App(); 54 | $handler = new \Core\Conf\Kyaaaa\Handler\Run(); 55 | $handler->allowQuit(false); 56 | $handler->writeToOutput(false); 57 | if ($getConf->environment() == 'development') { 58 | $handler->pushHandler(new \Core\Conf\Kyaaaa\Handler\Handler\KyaaaaDevelopmentHandler()); 59 | } else { 60 | $handler->pushHandler(new \Core\Conf\Kyaaaa\Handler\Handler\KyaaaaProductionHandler()); 61 | } 62 | $html = $handler->handleException($e); 63 | } 64 | return $this->connect; 65 | } 66 | 67 | /** 68 | * Set common PDO attributes 69 | */ 70 | private function setAttributes () 71 | { 72 | $this->connect->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); 73 | $this->connect->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 74 | $this->connect->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ); 75 | $this->connect->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_NATURAL); 76 | } 77 | 78 | /** 79 | * Connect PDO to MySQl database 80 | * @return void 81 | */ 82 | private function connectMySQl () 83 | { 84 | $this->connect = new \PDO("mysql:host={$this->host};port={$this->port};dbname={$this->database};charset={$this->charset}", $this->username, $this->password, $this->options); 85 | $this->setAttributes(); 86 | } 87 | 88 | /** 89 | * Connect PDO to PostgreSQl database 90 | * @return void 91 | */ 92 | private function connectPostgreSQl () 93 | { 94 | $this->connect = new \PDO("pgsql:host={$this->host};port={$this->port};dbname={$this->database}", $this->username, $this->password); 95 | $this->setAttributes(); 96 | } 97 | 98 | /** 99 | * Connect PDO to SQl Server database 100 | * @return void 101 | */ 102 | private function connectSQlServer () 103 | { 104 | $this->connect = new \PDO("sqlsrv:Server=".$this->host.";Connection=".$this->database."", $this->username, $this->password); 105 | $this->setAttributes(); 106 | } 107 | 108 | /** 109 | * Connect PDO to SQlite embedded database 110 | * @return void 111 | */ 112 | private function connectSQlite () 113 | { 114 | $this->connect = new \PDO("sqlite:".$this->sqlite_path); 115 | $this->setAttributes(); 116 | } 117 | } 118 | 119 | ?> -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/RunInterface.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler; 8 | 9 | use InvalidArgumentException; 10 | use Core\Conf\Kyaaaa\Handler\Exception\ErrorException; 11 | use Core\Conf\Kyaaaa\Handler\Handler\HandlerInterface; 12 | 13 | interface RunInterface 14 | { 15 | const EXCEPTION_HANDLER = "handleException"; 16 | const ERROR_HANDLER = "handleError"; 17 | const SHUTDOWN_HANDLER = "handleShutdown"; 18 | 19 | /** 20 | * Pushes a handler to the end of the stack 21 | * 22 | * @throws InvalidArgumentException If argument is not callable or instance of HandlerInterface 23 | * @param Callable|HandlerInterface $handler 24 | * @return Run 25 | */ 26 | public function pushHandler($handler); 27 | 28 | /** 29 | * Removes the last handler in the stack and returns it. 30 | * Returns null if there"s nothing else to pop. 31 | * 32 | * @return null|HandlerInterface 33 | */ 34 | public function popHandler(); 35 | 36 | /** 37 | * Returns an array with all handlers, in the 38 | * order they were added to the stack. 39 | * 40 | * @return array 41 | */ 42 | public function getHandlers(); 43 | 44 | /** 45 | * Clears all handlers in the handlerStack, including 46 | * the default PrettyPage handler. 47 | * 48 | * @return Run 49 | */ 50 | public function clearHandlers(); 51 | 52 | /** 53 | * Registers this instance as an error handler. 54 | * 55 | * @return Run 56 | */ 57 | public function register(); 58 | 59 | /** 60 | * Unregisters all handlers registered by this Core\App\Kyaaaa\Handler\Run instance 61 | * 62 | * @return Run 63 | */ 64 | public function unregister(); 65 | 66 | /** 67 | * Should Whoops allow Handlers to force the script to quit? 68 | * 69 | * @param bool|int $exit 70 | * @return bool 71 | */ 72 | public function allowQuit($exit = null); 73 | 74 | /** 75 | * Silence particular errors in particular files 76 | * 77 | * @param array|string $patterns List or a single regex pattern to match 78 | * @param int $levels Defaults to E_STRICT | E_DEPRECATED 79 | * @return \Core\Conf\Kyaaaa\Handler\Run 80 | */ 81 | public function silenceErrorsInPaths($patterns, $levels = 10240); 82 | 83 | /** 84 | * Should Whoops send HTTP error code to the browser if possible? 85 | * Whoops will by default send HTTP code 500, but you may wish to 86 | * use 502, 503, or another 5xx family code. 87 | * 88 | * @param bool|int $code 89 | * @return int|false 90 | */ 91 | public function sendHttpCode($code = null); 92 | 93 | /** 94 | * Should Whoops exit with a specific code on the CLI if possible? 95 | * Whoops will exit with 1 by default, but you can specify something else. 96 | * 97 | * @param int $code 98 | * @return int 99 | */ 100 | public function sendExitCode($code = null); 101 | 102 | /** 103 | * Should Whoops push output directly to the client? 104 | * If this is false, output will be returned by handleException 105 | * 106 | * @param bool|int $send 107 | * @return bool 108 | */ 109 | public function writeToOutput($send = null); 110 | 111 | /** 112 | * Handles an exception, ultimately generating a Whoops error 113 | * page. 114 | * 115 | * @param \Throwable $exception 116 | * @return string Output generated by handlers 117 | */ 118 | public function handleException($exception); 119 | 120 | /** 121 | * Converts generic PHP errors to \ErrorException 122 | * instances, before passing them off to be handled. 123 | * 124 | * This method MUST be compatible with set_error_handler. 125 | * 126 | * @param int $level 127 | * @param string $message 128 | * @param string $file 129 | * @param int $line 130 | * 131 | * @return bool 132 | * @throws ErrorException 133 | */ 134 | public function handleError($level, $message, $file = null, $line = null); 135 | 136 | /** 137 | * Special case to deal with Fatal errors and the like. 138 | */ 139 | public function handleShutdown(); 140 | } 141 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Route.php: -------------------------------------------------------------------------------- 1 | _path = trim($path, '/'); 16 | $this->callable = $callable; 17 | $this->_matches = []; 18 | $this->_params = []; 19 | $this->_get_params = []; 20 | $this->middleware_tab = []; 21 | $this->middleware_exist = false; 22 | } 23 | 24 | /** 25 | * @param string|null $url 26 | * @return bool 27 | */ 28 | function match(?string $url): bool 29 | { 30 | $url = trim($url, '/'); 31 | $path = preg_replace_callback('#:([\w]+)#', [$this, 'paramMatch'], $this->_path); 32 | $regex = "#^$path$#i"; 33 | if (!preg_match($regex, $url, $matches)) { 34 | return false; 35 | } 36 | array_shift($matches); 37 | array_shift($_GET); 38 | $this->_matches = $matches; 39 | foreach ($matches as $key => $val) { 40 | $_GET[$this->_get_params[$key]] = $val; 41 | } 42 | return true; 43 | } 44 | 45 | /** 46 | * 47 | */ 48 | function call() 49 | { 50 | try { 51 | if (count($this->middleware_tab) > 0) { 52 | $this->middleware_exist = false; 53 | foreach ($this->middleware_tab as $middleware) { 54 | $this->controllerMiddleware($middleware, true); 55 | } 56 | $this->middleware_tab = []; 57 | } 58 | $this->controllerMiddleware($this->callable); 59 | } catch (\Exception $ex) { 60 | echo $ex->getMessage(); 61 | } 62 | } 63 | 64 | /** 65 | * @param array $match 66 | * @return string 67 | */ 68 | private function paramMatch(array $match): string 69 | { 70 | if (isset($this->_params[$match[1]])) { 71 | return '(' . $this->_params[$match[1]] . ')'; 72 | } 73 | array_push($this->_get_params, $match[1]); 74 | return '([^/]+)'; 75 | } 76 | 77 | /** 78 | * @param $param 79 | * @param $regex 80 | * @return $this 81 | */ 82 | function with($param, $regex): Route 83 | { 84 | $this->_params[$param] = str_replace('(', '(?:', $regex); 85 | return $this; 86 | } 87 | 88 | /** 89 | * @return array 90 | */ 91 | function getmatch(): array 92 | { 93 | return $this->_matches; 94 | } 95 | 96 | /** 97 | * @param $params 98 | * @return array|string|string[] 99 | */ 100 | function getUrl($params) 101 | { 102 | $path = $this->_path; 103 | foreach ($params as $k => $v) { 104 | $path = str_replace(":$k", $v, $path); 105 | } 106 | return $path; 107 | } 108 | 109 | /** 110 | * @param $middleware 111 | * @return $this 112 | */ 113 | function middleware($middleware): Route 114 | { 115 | $this->middleware_tab[] = $middleware; 116 | return $this; 117 | } 118 | 119 | /** 120 | * @param $callable 121 | * @param bool $is_middleware 122 | */ 123 | private function controllerMiddleware($callable, bool $is_middleware = false): void 124 | { 125 | try { 126 | if (is_string($callable) || is_array($callable)) { 127 | $params = is_string($callable) ? explode('#', $callable) : $callable; 128 | if (count($params) != 2) { 129 | throw new \Exception("Error : on class/method is not well defined"); 130 | } 131 | $class_name = $params[0]; 132 | $class_method = $params[1]; 133 | $class_instance = new $class_name; 134 | if (!method_exists($class_instance, $class_method)) { 135 | throw new \Exception("method : $class_method does not belong the class : $class_name."); 136 | } 137 | call_user_func_array([$class_instance, $class_method], $this->_matches); 138 | } else { 139 | if (isset($callable) && is_callable($callable, true)) { 140 | call_user_func_array($callable, $this->_matches); 141 | } 142 | } 143 | return; 144 | } catch (\Exception $ex) { 145 | print_r($ex->getMessage()); 146 | exit(); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Router.php: -------------------------------------------------------------------------------- 1 | baseRoute = ''; 13 | $this->routes = []; 14 | $this->_nameRoute = []; 15 | $this->_url = $_SERVER['REQUEST_URI']; 16 | $this->namespace = ""; 17 | } 18 | 19 | /** 20 | * GET method 21 | * @param string $path 22 | * @param $callable 23 | * @param string|null $name 24 | * @return Route 25 | */ 26 | function get(string $path, $callable, ?string $name = null): Route 27 | { 28 | return $this->add($path, $callable, 'GET', $name); 29 | } 30 | 31 | /** 32 | * POST method 33 | * @param string $path 34 | * @param $callable 35 | * @param string|null $name 36 | * @return Route 37 | */ 38 | function post(string $path, $callable, ?string $name = null): Route 39 | { 40 | return $this->add($path, $callable, 'POST', $name); 41 | } 42 | 43 | /** 44 | * DELETE method 45 | * @param string $path 46 | * @param $callable 47 | * @param string|null $name 48 | * @return Route 49 | */ 50 | function delete(string $path, $callable, ?string $name = null): Route 51 | { 52 | return $this->add($path, $callable, 'DELETE', $name); 53 | } 54 | 55 | /** 56 | * PUT method 57 | * @param string $path 58 | * @param $callable 59 | * @param string|null $name 60 | * @return Route 61 | */ 62 | function put(string $path, $callable, ?string $name = null): Route 63 | { 64 | return $this->add($path, $callable, 'PUT', $name); 65 | } 66 | 67 | /** 68 | * @param string $base_route 69 | * @param callable $callable 70 | */ 71 | function group(string $base_route, callable $callable): void 72 | { 73 | $cur_base_route = $this->baseRoute; 74 | $this->baseRoute .= $base_route; 75 | call_user_func($callable); 76 | $this->baseRoute = $cur_base_route; 77 | } 78 | 79 | /** 80 | * @param string $path 81 | * @param $callable $callable 82 | * @param string|null $name 83 | * @param string $method 84 | * @return Route 85 | */ 86 | private function add(string $path, $callable, string $method, ?string $name = null): Route 87 | { 88 | $path = $this->baseRoute . '/' . trim($path, '/'); 89 | $path = $this->baseRoute ? rtrim($path, '/') : $path; 90 | 91 | $route = new Route($path, $callable); 92 | $this->routes[$method][] = $route; 93 | 94 | if (is_string($callable) && $name == null) { 95 | $name = $callable; 96 | } 97 | 98 | if ($name) { 99 | $this->_nameRoute[$name] = $route; 100 | } 101 | return $route; 102 | } 103 | 104 | /** 105 | * @param string $name 106 | * @param array $params 107 | * @return string 108 | */ 109 | function url(string $name, array $params = []): string 110 | { 111 | try { 112 | if (!isset($this->_nameRoute[$name])) { 113 | throw new \Exception('No route match'); 114 | } 115 | return $this->_nameRoute[$name]->geturl($params); 116 | } catch (\Exception $ex) { 117 | return $ex->getMessage(); 118 | } 119 | } 120 | 121 | /** 122 | * @return mixed 123 | */ 124 | function run() 125 | { 126 | error_reporting(0); 127 | require_once __DIR__ . "/Common.php"; 128 | 129 | try { 130 | if (!isset($this->routes[$_SERVER['REQUEST_METHOD']])) { 131 | throw new \Exception('Request method is not defined '); 132 | } 133 | $routesRequestMethod = $this->routes[$_SERVER['REQUEST_METHOD']]; 134 | $i = 0; 135 | foreach ($routesRequestMethod as $route) { 136 | if ($route->match($this->_url)) { 137 | return $route->call(); 138 | } else { 139 | $i++; 140 | } 141 | } 142 | if (count($routesRequestMethod) === $i) { 143 | header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); 144 | echo 'Kyaaaa~ 404 !
'.http_response_code().': Not Found
'; 145 | exit; 146 | } 147 | } catch (\Exception $ex) { 148 | echo $ex->getMessage(); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Resources/css/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.24.1 2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ 3 | /** 4 | * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML 5 | * Based on https://github.com/chriskempson/tomorrow-theme 6 | * @author Rose Pritchard 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: #ccc; 12 | background: none; 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | font-size: 1em; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | 31 | } 32 | 33 | /* Code blocks */ 34 | pre[class*="language-"] { 35 | padding: 1em; 36 | margin: .5em 0; 37 | overflow: auto; 38 | } 39 | 40 | :not(pre) > code[class*="language-"], 41 | pre[class*="language-"] { 42 | background: #2d2d2d; 43 | } 44 | 45 | /* Inline code */ 46 | :not(pre) > code[class*="language-"] { 47 | padding: .1em; 48 | border-radius: .3em; 49 | white-space: normal; 50 | } 51 | 52 | .token.comment, 53 | .token.block-comment, 54 | .token.prolog, 55 | .token.doctype, 56 | .token.cdata { 57 | color: #999; 58 | } 59 | 60 | .token.punctuation { 61 | color: #ccc; 62 | } 63 | 64 | .token.tag, 65 | .token.attr-name, 66 | .token.namespace, 67 | .token.deleted { 68 | color: #e2777a; 69 | } 70 | 71 | .token.function-name { 72 | color: #6196cc; 73 | } 74 | 75 | .token.boolean, 76 | .token.number, 77 | .token.function { 78 | color: #f08d49; 79 | } 80 | 81 | .token.property, 82 | .token.class-name, 83 | .token.constant, 84 | .token.symbol { 85 | color: #f8c555; 86 | } 87 | 88 | .token.selector, 89 | .token.important, 90 | .token.atrule, 91 | .token.keyword, 92 | .token.builtin { 93 | color: #cc99cd; 94 | } 95 | 96 | .token.string, 97 | .token.char, 98 | .token.attr-value, 99 | .token.regex, 100 | .token.variable { 101 | color: #7ec699; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url { 107 | color: #67cdcc; 108 | } 109 | 110 | .token.important, 111 | .token.bold { 112 | font-weight: bold; 113 | } 114 | .token.italic { 115 | font-style: italic; 116 | } 117 | 118 | .token.entity { 119 | cursor: help; 120 | } 121 | 122 | .token.inserted { 123 | color: green; 124 | } 125 | 126 | pre[data-line] { 127 | position: relative; 128 | padding: 1em 0 1em 3em; 129 | } 130 | 131 | .line-highlight { 132 | position: absolute; 133 | left: 0; 134 | right: 0; 135 | padding: inherit 0; 136 | margin-top: 1em; /* Same as .prism’s padding-top */ 137 | 138 | background: hsla(24, 20%, 50%,.08); 139 | background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); 140 | 141 | pointer-events: none; 142 | 143 | line-height: inherit; 144 | white-space: pre; 145 | } 146 | 147 | @media print { 148 | .line-highlight { 149 | /* 150 | * This will prevent browsers from replacing the background color with white. 151 | * It's necessary because the element is layered on top of the displayed code. 152 | */ 153 | -webkit-print-color-adjust: exact; 154 | color-adjust: exact; 155 | } 156 | } 157 | 158 | .line-highlight:before, 159 | .line-highlight[data-end]:after { 160 | content: attr(data-start); 161 | position: absolute; 162 | top: .4em; 163 | left: .6em; 164 | min-width: 1em; 165 | padding: 0 .5em; 166 | background-color: hsla(24, 20%, 50%,.4); 167 | color: hsl(24, 20%, 95%); 168 | font: bold 65%/1.5 sans-serif; 169 | text-align: center; 170 | vertical-align: .3em; 171 | border-radius: 999px; 172 | text-shadow: none; 173 | box-shadow: 0 1px white; 174 | } 175 | 176 | .line-highlight[data-end]:after { 177 | content: attr(data-end); 178 | top: auto; 179 | bottom: .4em; 180 | } 181 | 182 | .line-numbers .line-highlight:before, 183 | .line-numbers .line-highlight:after { 184 | content: none; 185 | } 186 | 187 | pre[id].linkable-line-numbers span.line-numbers-rows { 188 | pointer-events: all; 189 | } 190 | pre[id].linkable-line-numbers span.line-numbers-rows > span:before { 191 | cursor: pointer; 192 | } 193 | pre[id].linkable-line-numbers span.line-numbers-rows > span:hover:before { 194 | background-color: rgba(128, 128, 128, .2); 195 | } 196 | 197 | pre[class*="language-"].line-numbers { 198 | position: relative; 199 | padding-left: 3.8em; 200 | counter-reset: linenumber; 201 | } 202 | 203 | pre[class*="language-"].line-numbers > code { 204 | position: relative; 205 | white-space: inherit; 206 | } 207 | 208 | .line-numbers .line-numbers-rows { 209 | position: absolute; 210 | pointer-events: none; 211 | top: 0; 212 | font-size: 100%; 213 | left: -3.8em; 214 | width: 3em; /* works for line-numbers below 1000 lines */ 215 | letter-spacing: -1px; 216 | border-right: 1px solid #999; 217 | 218 | -webkit-user-select: none; 219 | -moz-user-select: none; 220 | -ms-user-select: none; 221 | user-select: none; 222 | 223 | } 224 | 225 | .line-numbers-rows > span { 226 | display: block; 227 | counter-increment: linenumber; 228 | } 229 | 230 | .line-numbers-rows > span:before { 231 | content: counter(linenumber); 232 | color: #999; 233 | display: block; 234 | padding-right: 0.8em; 235 | text-align: right; 236 | } 237 | 238 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Request.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Exception; 8 | 9 | use ArrayAccess; 10 | use ArrayIterator; 11 | use Countable; 12 | use IteratorAggregate; 13 | use ReturnTypeWillChange; 14 | use Serializable; 15 | use UnexpectedValueException; 16 | 17 | /** 18 | * Exposes a fluent interface for dealing with an ordered list 19 | * of stack-trace frames. 20 | */ 21 | class FrameCollection implements ArrayAccess, IteratorAggregate, Serializable, Countable 22 | { 23 | /** 24 | * @var array[] 25 | */ 26 | private $frames; 27 | 28 | /** 29 | * @param array $frames 30 | */ 31 | public function __construct(array $frames) 32 | { 33 | $this->frames = array_map(function ($frame) { 34 | return new Frame($frame); 35 | }, $frames); 36 | } 37 | 38 | /** 39 | * Filters frames using a callable, returns the same FrameCollection 40 | * 41 | * @param callable $callable 42 | * @return FrameCollection 43 | */ 44 | public function filter($callable) 45 | { 46 | $this->frames = array_values(array_filter($this->frames, $callable)); 47 | return $this; 48 | } 49 | 50 | /** 51 | * Map the collection of frames 52 | * 53 | * @param callable $callable 54 | * @return FrameCollection 55 | */ 56 | public function map($callable) 57 | { 58 | // Contain the map within a higher-order callable 59 | // that enforces type-correctness for the $callable 60 | $this->frames = array_map(function ($frame) use ($callable) { 61 | $frame = call_user_func($callable, $frame); 62 | 63 | if (!$frame instanceof Frame) { 64 | throw new UnexpectedValueException( 65 | "Callable to " . __CLASS__ . "::map must return a Frame object" 66 | ); 67 | } 68 | 69 | return $frame; 70 | }, $this->frames); 71 | 72 | return $this; 73 | } 74 | 75 | /** 76 | * Returns an array with all frames, does not affect 77 | * the internal array. 78 | * 79 | * @todo If this gets any more complex than this, 80 | * have getIterator use this method. 81 | * @see FrameCollection::getIterator 82 | * @return array 83 | */ 84 | public function getArray() 85 | { 86 | return $this->frames; 87 | } 88 | 89 | /** 90 | * @see IteratorAggregate::getIterator 91 | * @return ArrayIterator 92 | */ 93 | #[ReturnTypeWillChange] 94 | public function getIterator() 95 | { 96 | return new ArrayIterator($this->frames); 97 | } 98 | 99 | /** 100 | * @see ArrayAccess::offsetExists 101 | * @param int $offset 102 | */ 103 | #[ReturnTypeWillChange] 104 | public function offsetExists($offset) 105 | { 106 | return isset($this->frames[$offset]); 107 | } 108 | 109 | /** 110 | * @see ArrayAccess::offsetGet 111 | * @param int $offset 112 | */ 113 | #[ReturnTypeWillChange] 114 | public function offsetGet($offset) 115 | { 116 | return $this->frames[$offset]; 117 | } 118 | 119 | /** 120 | * @see ArrayAccess::offsetSet 121 | * @param int $offset 122 | */ 123 | #[ReturnTypeWillChange] 124 | public function offsetSet($offset, $value) 125 | { 126 | throw new \Exception(__CLASS__ . ' is read only'); 127 | } 128 | 129 | /** 130 | * @see ArrayAccess::offsetUnset 131 | * @param int $offset 132 | */ 133 | #[ReturnTypeWillChange] 134 | public function offsetUnset($offset) 135 | { 136 | throw new \Exception(__CLASS__ . ' is read only'); 137 | } 138 | 139 | /** 140 | * @see Countable::count 141 | * @return int 142 | */ 143 | #[ReturnTypeWillChange] 144 | public function count() 145 | { 146 | return count($this->frames); 147 | } 148 | 149 | /** 150 | * Count the frames that belongs to the application. 151 | * 152 | * @return int 153 | */ 154 | public function countIsApplication() 155 | { 156 | return count(array_filter($this->frames, function (Frame $f) { 157 | return $f->isApplication(); 158 | })); 159 | } 160 | 161 | /** 162 | * @see Serializable::serialize 163 | * @return string 164 | */ 165 | #[ReturnTypeWillChange] 166 | public function serialize() 167 | { 168 | return serialize($this->frames); 169 | } 170 | 171 | /** 172 | * @see Serializable::unserialize 173 | * @param string $serializedFrames 174 | */ 175 | #[ReturnTypeWillChange] 176 | public function unserialize($serializedFrames) 177 | { 178 | $this->frames = unserialize($serializedFrames); 179 | } 180 | 181 | public function __serialize() 182 | { 183 | return $this->frames; 184 | } 185 | 186 | public function __unserialize(array $serializedFrames) 187 | { 188 | $this->frames = $serializedFrames; 189 | } 190 | 191 | /** 192 | * @param Frame[] $frames Array of Frame instances, usually from $e->getPrevious() 193 | */ 194 | public function prependFrames(array $frames) 195 | { 196 | $this->frames = array_merge($frames, $this->frames); 197 | } 198 | 199 | /** 200 | * Gets the innermost part of stack trace that is not the same as that of outer exception 201 | * 202 | * @param FrameCollection $parentFrames Outer exception frames to compare tail against 203 | * @return Frame[] 204 | */ 205 | public function topDiff(FrameCollection $parentFrames) 206 | { 207 | $diff = $this->frames; 208 | 209 | $parentFrames = $parentFrames->getArray(); 210 | $p = count($parentFrames)-1; 211 | 212 | for ($i = count($diff)-1; $i >= 0 && $p >= 0; $i--) { 213 | /** @var Frame $tailFrame */ 214 | $tailFrame = $diff[$i]; 215 | if ($tailFrame->equals($parentFrames[$p])) { 216 | unset($diff[$i]); 217 | } 218 | $p--; 219 | } 220 | return $diff; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /core/Controllers/PaymentCtrl.php: -------------------------------------------------------------------------------- 1 | PaymentModel = new PaymentModel(); 9 | $this->request = request(); 10 | $this->tripay = new Tripay(); 11 | } 12 | 13 | public function index() { 14 | $username = $this->DonateModel->get_username(); 15 | $data['title'] = 'Dukung @' . $username; 16 | $data['username'] = $username; 17 | return view('donate/index', $data); 18 | } 19 | 20 | public function do_donate() { 21 | $name = $this->request->post('name'); 22 | $email = $this->request->post('email'); 23 | $amount = $this->request->post('amount'); 24 | $msgs = $this->request->post('msgs'); 25 | $private = $this->request->post('private'); 26 | 27 | if (profanity($name) == true || profanity($msgs) == true) { 28 | echo json_encode([ 29 | 'success' => false, 30 | 'invoice' => '', 31 | 'msg' => 'Jangan berkata kasar kek gitu la' 32 | ]); 33 | exit; 34 | } 35 | 36 | $payload = [ 37 | 'isDonation' => true, 38 | 'name' => $name, 39 | 'email' => $email, 40 | 'amount' => $amount, 41 | ]; 42 | 43 | $order = $this->tripay->request_payment($payload); 44 | if ($order->success == true) { 45 | $data = [ 46 | 'reference' => $order->data->reference, 47 | 'merchant_ref' => $order->data->merchant_ref, 48 | 'customer_name' => $name, 49 | 'customer_email' => $email, 50 | 'customer_phone' => $order->data->customer_phone, 51 | 'payment_name' => $order->data->payment_name, 52 | 'amount' => $order->data->amount, 53 | 'amount_received' => $order->data->amount_received, 54 | 'checkout_url' => $order->data->checkout_url, 55 | 'invoice_url' => url() . '/inv/' . $order->data->reference, 56 | 'msgs' => $msgs, 57 | 'status' => 'UNPAID', 58 | 'private' => $private 59 | ]; 60 | $insert_donate = $this->PaymentModel->save_donation($data); 61 | if ($insert_donate) { 62 | echo json_encode([ 63 | 'success' => true, 64 | 'invoice' => url() . 'inv/' . $order->data->reference, 65 | 'msg' => '' 66 | ]); 67 | } else { 68 | echo json_encode([ 69 | 'success' => false, 70 | 'invoice' => '', 71 | 'msg' => 'Gagal membuat transaksi, silahkan coba lagi...' 72 | ]); 73 | } 74 | } else { 75 | echo json_encode([ 76 | 'success' => false, 77 | 'invoice' => '', 78 | 'msg' => $order->message 79 | ]); 80 | } 81 | } 82 | 83 | public function invoice($id) { 84 | $data['response'] = $this->tripay->invoice($id); 85 | $payment_code = $data['response']->data->payment_method; 86 | $data['icon'] = $this->tripay->icon($payment_code); 87 | $data['settings'] = $this->PaymentModel->get_settings(); 88 | return view('invoice/index', $data); 89 | } 90 | 91 | public function callback() { 92 | $data = $this->tripay->callback(); 93 | $get = $this->PaymentModel->get_merchant_ref($data->merchant_ref); 94 | if (empty($get)) { 95 | exit(json_encode([ 96 | 'success' => false, 97 | 'message' => 'merchant_ref not found', 98 | ])); 99 | } 100 | $update = $this->PaymentModel->update_donation($data->merchant_ref ,$data->status); 101 | if ($update) { 102 | echo json_encode(['success' => true]); 103 | if ($data->status == 'PAID') { 104 | $pusher = $this->tripay->pusher(); 105 | $push['name'] = $get[0]->customer_name; 106 | $push['amount'] = 'Rp ' . number_format($get[0]->amount,0,',','.'); 107 | $push['jumlah'] = $get[0]->amount; 108 | $push['msgs'] = $get[0]->msgs; 109 | $push['merchant_ref'] = $get[0]->merchant_ref; 110 | $pusher->trigger('my_stream', 'donate_event', $push); 111 | 112 | $email_body = '

Halo, '.$get[0]->customer_name .'

Terima kasih, ya untuk donasinya! Berikut detail pembayarannya:

Invoice link '.$get[0]->invoice_url .'
Nama '.$get[0]->customer_name .'
Metode Pembayaran '.$get[0]->payment_name .'
Total '.$get[0]->amount .'
Waktu Pembayaran '.date('d/m/Y H:i:s', $data->paid_at).'

Terima Kasih'; 113 | 114 | $email = \Core\Conf\Email::start(); 115 | $email->setFrom('naufspace@gmail.com', 'Nauf Space'); 116 | $email->setTo($get[0]->customer_email, $get[0]->customer_name); 117 | $email->setSubject('Pembayaran dengan '.$get[0]->payment_name.' Berhasil tanggal ' . date('d/m/Y H:i:s', $data->paid_at)); 118 | $email->setBody($email_body); 119 | $email->send(); 120 | } 121 | } 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /core/Views/donate/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Views/streamoverlay/donatenotification/layout.kyaaaa.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Donate Notifications 4 | 5 | 25 | 26 | 27 | 28 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 121 | 122 | 123 | 124 | 125 | 178 | 179 | -------------------------------------------------------------------------------- /donateapp_db.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 5.1.1 3 | -- https://www.phpmyadmin.net/ 4 | -- 5 | -- Host: 127.0.0.1 6 | -- Generation Time: Oct 02, 2022 at 07:16 PM 7 | -- Server version: 10.4.22-MariaDB 8 | -- PHP Version: 7.4.27 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | START TRANSACTION; 12 | SET time_zone = "+00:00"; 13 | 14 | 15 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 16 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 17 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 18 | /*!40101 SET NAMES utf8mb4 */; 19 | 20 | -- 21 | -- Database: `donateapp_db` 22 | -- 23 | 24 | -- -------------------------------------------------------- 25 | 26 | -- 27 | -- Table structure for table `donations` 28 | -- 29 | 30 | CREATE TABLE `donations` ( 31 | `id` int(11) NOT NULL, 32 | `reference` varchar(255) NOT NULL, 33 | `merchant_ref` varchar(255) NOT NULL, 34 | `customer_name` varchar(255) NOT NULL, 35 | `customer_email` varchar(255) NOT NULL, 36 | `customer_phone` varchar(255) NOT NULL, 37 | `payment_name` varchar(255) NOT NULL, 38 | `amount` varchar(255) NOT NULL, 39 | `amount_received` varchar(255) NOT NULL, 40 | `checkout_url` varchar(255) NOT NULL, 41 | `invoice_url` varchar(255) NOT NULL, 42 | `msgs` varchar(255) DEFAULT NULL, 43 | `status` varchar(255) NOT NULL, 44 | `private` varchar(255) DEFAULT NULL, 45 | `created_at` timestamp NOT NULL DEFAULT current_timestamp(), 46 | `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() 47 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 48 | 49 | -- 50 | -- Dumping data for table `donations` 51 | -- 52 | 53 | INSERT INTO `donations` (`id`, `reference`, `merchant_ref`, `customer_name`, `customer_email`, `customer_phone`, `payment_name`, `amount`, `amount_received`, `checkout_url`, `invoice_url`, `msgs`, `status`, `private`, `created_at`, `updated_at`) VALUES 54 | (20, 'DEV-T1174062377O2C1C', 'INV97403', 'Alwi', 'ztgsk8@gmail.com', '081249397403', 'QRIS (Customizable)', '25000', '24025', 'https://tripay.co.id/checkout/DEV-T1174062377O2C1C', 'http://localhost:5555//inv/DEV-T1174062377O2C1C', 'Semangat mas', 'PAID', 'yes', '2022-10-01 09:15:45', '2022-10-02 16:31:19'), 55 | (21, 'DEV-T1174062380TX1PV', 'INV90889', 'Arfy', 'nauf@gmail.com', '081278690889', 'QRIS (Customizable)', '200000', '197800', 'https://tripay.co.id/checkout/DEV-T1174062380TX1PV', 'http://localhost:5555//inv/DEV-T1174062380TX1PV', 'nih 200k huhuy', 'PAID', 'no', '2022-10-01 10:06:29', '2022-10-02 17:16:12'), 56 | (22, 'DEV-T1174062381NEIFU', 'INV80499', 'Pace', 'nauf@gmail.com', '081232280499', 'QRIS (Customizable)', '200000', '197800', 'https://tripay.co.id/checkout/DEV-T1174062381NEIFU', 'http://localhost:5555//inv/DEV-T1174062381NEIFU', 'main fallguys dong', 'PAID', 'no', '2022-10-01 10:06:39', '2022-10-02 16:26:30'), 57 | (23, 'DEV-T11740623821VUA2', 'INV74362', 'Komodo', 'nauf@gmail.com', '081243074362', 'QRIS (Customizable)', '200000', '197800', 'https://tripay.co.id/checkout/DEV-T11740623821VUA2', 'http://localhost:5555//inv/DEV-T11740623821VUA2', 'a keong a keong a keong', 'PAID', 'no', '2022-10-01 10:06:52', '2022-10-02 16:27:56'), 58 | (24, 'DEV-T11740623831FGHZ', 'INV86185', 'Ahmad', 'dasdasd@asdasd.com', '081245786185', 'QRIS (Customizable)', '200000', '197800', 'https://tripay.co.id/checkout/DEV-T11740623831FGHZ', 'http://localhost:5555//inv/DEV-T11740623831FGHZ', 'gaskeun lah', 'PAID', 'no', '2022-10-01 10:07:17', '2022-10-02 16:28:39'), 59 | (25, 'DEV-T1174062384SRAJB', 'INV75915', 'Ahmad', 'dasdasd@asdasd.com', '081213475915', 'QRIS (Customizable)', '200000', '197800', 'https://tripay.co.id/checkout/DEV-T1174062384SRAJB', 'http://localhost:5555//inv/DEV-T1174062384SRAJB', 'Kali lagi nih', 'UNPAID', 'no', '2022-10-01 10:07:25', '2022-10-02 16:29:55'), 60 | (26, 'DEV-T11740623859NYUA', 'INV07115', 'Jul', 'nauf@gmail.com', '081223707115', 'QRIS (Customizable)', '25000', '24025', 'https://tripay.co.id/checkout/DEV-T11740623859NYUA', 'http://localhost:5555//inv/DEV-T11740623859NYUA', 'lanjut semangat', 'PAID', 'no', '2022-10-01 10:41:26', '2022-10-02 16:30:48'), 61 | (27, 'DEV-T1174062401QKDYB', 'INV92282', 'Arfy', 'nauf@na.com', '081271292282', 'QRIS by ShopeePay', '25000', '24075', 'https://tripay.co.id/checkout/DEV-T1174062401QKDYB', 'http://localhost:5555//inv/DEV-T1174062401QKDYB', 'Stream ngoding dong kak', 'PAID', 'no', '2022-10-01 15:45:51', '2022-10-02 16:30:18'), 62 | (28, 'DEV-T1174062402EVYGK', 'INV14076', 'Komodo', 'ztgasa@gmail.com', '081238714076', 'QRIS', '10000', '9180', 'https://tripay.co.id/checkout/DEV-T1174062402EVYGK', 'http://localhost:5555//inv/DEV-T1174062402EVYGK', 'Oalah malah streaming', 'PAID', 'no', '2022-10-01 15:46:21', '2022-10-02 16:29:47'), 63 | (29, 'DEV-T1174062473GD7BA', 'INV22345', 'Seseorang', 'pace@dean.com', '081294322345', 'QRIS (Customizable)', '300000', '297100', 'https://tripay.co.id/checkout/DEV-T1174062473GD7BA', 'http://localhost:5555//inv/DEV-T1174062473GD7BA', 'Buat nasi uduk', 'PAID', 'yes', '2022-10-02 15:50:24', '2022-10-02 16:29:49'); 64 | 65 | -- -------------------------------------------------------- 66 | 67 | -- 68 | -- Table structure for table `settings` 69 | -- 70 | 71 | CREATE TABLE `settings` ( 72 | `id` int(11) NOT NULL, 73 | `merchant_code` varchar(255) NOT NULL, 74 | `merchant_api_key` varchar(255) NOT NULL, 75 | `merchant_private_key` varchar(255) NOT NULL, 76 | `endpoint` varchar(255) NOT NULL, 77 | `pusher_app_id` varchar(255) NOT NULL, 78 | `pusher_key` varchar(255) NOT NULL, 79 | `pusher_secret` varchar(255) NOT NULL, 80 | `pusher_cluster` varchar(255) NOT NULL 81 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 82 | 83 | -- 84 | -- Dumping data for table `settings` 85 | -- 86 | 87 | INSERT INTO `settings` (`id`, `merchant_code`, `merchant_api_key`, `merchant_private_key`, `endpoint`, `pusher_app_id`, `pusher_key`, `pusher_secret`, `pusher_cluster`) VALUES 88 | (1, '', '', '', 'api-sandbox', '', '', '', ''); 89 | 90 | -- -------------------------------------------------------- 91 | 92 | -- 93 | -- Table structure for table `users` 94 | -- 95 | 96 | CREATE TABLE `users` ( 97 | `id` int(11) NOT NULL, 98 | `name` varchar(255) NOT NULL, 99 | `username` varchar(255) DEFAULT NULL, 100 | `email` varchar(255) NOT NULL, 101 | `password` varchar(255) NOT NULL, 102 | `roles` varchar(255) NOT NULL, 103 | `fb` varchar(255) NOT NULL, 104 | `ig` varchar(255) NOT NULL, 105 | `linkedin` varchar(255) NOT NULL, 106 | `yt` varchar(255) NOT NULL, 107 | `twitch` varchar(255) NOT NULL, 108 | `twitter` varchar(255) NOT NULL, 109 | `github` varchar(255) NOT NULL, 110 | `created_at` timestamp NOT NULL DEFAULT current_timestamp() 111 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 112 | 113 | -- 114 | -- Dumping data for table `users` 115 | -- 116 | 117 | INSERT INTO `users` (`id`, `name`, `username`, `email`, `password`, `roles`, `fb`, `ig`, `linkedin`, `yt`, `twitch`, `twitter`, `github`, `created_at`) VALUES 118 | (1, 'Kyaaaa', 'kyaaaa', 'demo@demo.com', '$2y$10$HKSdf05cvIYrdzbuiALWdevR6/rJ9ce86XoN1FL7buhIhSCZxvwRS', '1', '', '', '', 'https://youtube.com', '', '', 'https://github.com/naufkia', '2022-06-08 02:36:42'); 119 | 120 | -- 121 | -- Indexes for dumped tables 122 | -- 123 | 124 | -- 125 | -- Indexes for table `donations` 126 | -- 127 | ALTER TABLE `donations` 128 | ADD PRIMARY KEY (`id`); 129 | 130 | -- 131 | -- Indexes for table `settings` 132 | -- 133 | ALTER TABLE `settings` 134 | ADD PRIMARY KEY (`id`); 135 | 136 | -- 137 | -- Indexes for table `users` 138 | -- 139 | ALTER TABLE `users` 140 | ADD PRIMARY KEY (`id`); 141 | 142 | -- 143 | -- AUTO_INCREMENT for dumped tables 144 | -- 145 | 146 | -- 147 | -- AUTO_INCREMENT for table `donations` 148 | -- 149 | ALTER TABLE `donations` 150 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=30; 151 | 152 | -- 153 | -- AUTO_INCREMENT for table `settings` 154 | -- 155 | ALTER TABLE `settings` 156 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; 157 | 158 | -- 159 | -- AUTO_INCREMENT for table `users` 160 | -- 161 | ALTER TABLE `users` 162 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; 163 | COMMIT; 164 | 165 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 166 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 167 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 168 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Resources/js/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v1.5.3 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ar;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n');var $el=$this.find(".js-marquee").css({"margin-right":o.gap,float:"left"});if(o.duplicated){$el.clone(true).appendTo($this)}$this.wrapInner('
');$marqueeWrapper=$this.find(".js-marquee-wrapper");if(verticalDir){var containerHeight=$this.height();$marqueeWrapper.removeAttr("style");$this.height(containerHeight);$this.find(".js-marquee").css({float:"none","margin-bottom":o.gap,"margin-right":0});if(o.duplicated){$this.find(".js-marquee:last").css({"margin-bottom":0})}var elHeight=$this.find(".js-marquee:first").height()+o.gap;if(o.startVisible&&!o.duplicated){o._completeDuration=(parseInt(elHeight,10)+parseInt(containerHeight,10))/parseInt(containerHeight,10)*o.duration;o.duration=parseInt(elHeight,10)/parseInt(containerHeight,10)*o.duration}else{o.duration=(parseInt(elHeight,10)+parseInt(containerHeight,10))/parseInt(containerHeight,10)*o.duration}}else{elWidth=$this.find(".js-marquee:first").width()+o.gap;containerWidth=$this.width();if(o.startVisible&&!o.duplicated){o._completeDuration=(parseInt(elWidth,10)+parseInt(containerWidth,10))/parseInt(containerWidth,10)*o.duration;o.duration=parseInt(elWidth,10)/parseInt(containerWidth,10)*o.duration}else{o.duration=(parseInt(elWidth,10)+parseInt(containerWidth,10))/parseInt(containerWidth,10)*o.duration}}if(o.duplicated){o.duration=o.duration/2}if(o.allowCss3Support){var elm=document.body||document.createElement("div"),animationName="marqueeAnimation-"+Math.floor(Math.random()*1e7),domPrefixes="Webkit Moz O ms Khtml".split(" "),animationString="animation",animationCss3Str="",keyframeString="";if(elm.style.animation!==undefined){keyframeString="@keyframes "+animationName+" ";css3AnimationIsSupported=true}if(css3AnimationIsSupported===false){for(var i=0;i2){$marqueeWrapper.css("transform","translateY("+(o.direction==="up"?0:"-"+elHeight+"px")+")")}animationCss={transform:"translateY("+(o.direction==="up"?"-"+elHeight+"px":0)+")"}}else if(o.startVisible){if(loopCount===2){if(animationCss3Str){animationCss3Str=animationName+" "+o.duration/1e3+"s "+o.delayBeforeStart/1e3+"s "+o.css3easing}animationCss={transform:"translateY("+(o.direction==="up"?"-"+elHeight+"px":containerHeight+"px")+")"};loopCount++}else if(loopCount===3){o.duration=o._completeDuration;if(animationCss3Str){animationName=animationName+"0";keyframeString=$.trim(keyframeString)+"0 ";animationCss3Str=animationName+" "+o.duration/1e3+"s 0s infinite "+o.css3easing}_rePositionVertically()}}else{_rePositionVertically();animationCss={transform:"translateY("+(o.direction==="up"?"-"+$marqueeWrapper.height()+"px":containerHeight+"px")+")"}}}else{if(o.duplicated){if(loopCount>2){$marqueeWrapper.css("transform","translateX("+(o.direction==="left"?0:"-"+elWidth+"px")+")")}animationCss={transform:"translateX("+(o.direction==="left"?"-"+elWidth+"px":0)+")"}}else if(o.startVisible){if(loopCount===2){if(animationCss3Str){animationCss3Str=animationName+" "+o.duration/1e3+"s "+o.delayBeforeStart/1e3+"s "+o.css3easing}animationCss={transform:"translateX("+(o.direction==="left"?"-"+elWidth+"px":containerWidth+"px")+")"};loopCount++}else if(loopCount===3){o.duration=o._completeDuration;if(animationCss3Str){animationName=animationName+"0";keyframeString=$.trim(keyframeString)+"0 ";animationCss3Str=animationName+" "+o.duration/1e3+"s 0s infinite "+o.css3easing}_rePositionHorizontally()}}else{_rePositionHorizontally();animationCss={transform:"translateX("+(o.direction==="left"?"-"+elWidth+"px":containerWidth+"px")+")"}}}$this.trigger("beforeStarting");if(css3AnimationIsSupported){$marqueeWrapper.css(animationString,animationCss3Str);var keyframeCss=keyframeString+" { 100% "+_objToString(animationCss)+"}",$styles=$marqueeWrapper.find("style");if($styles.length!==0){$styles.filter(":last").html(keyframeCss)}else{$("head").append("")}_prefixedEvent($marqueeWrapper[0],"AnimationIteration",function(){$this.trigger("finished")});_prefixedEvent($marqueeWrapper[0],"AnimationEnd",function(){animate();$this.trigger("finished")})}else{$marqueeWrapper.animate(animationCss,o.duration,o.easing,function(){$this.trigger("finished");if(o.pauseOnCycle){_startAnimationWithDelay()}else{animate()}})}$this.data("runningStatus","resumed")};$this.on("pause",methods.pause);$this.on("resume",methods.resume);if(o.pauseOnHover){$this.on("mouseenter",methods.pause);$this.on("mouseleave",methods.resume)}if(css3AnimationIsSupported&&o.allowCss3Support){animate()}else{_startAnimationWithDelay()}})};$.fn.marquee.defaults={allowCss3Support:true,css3easing:"linear",easing:"linear",delayBeforeStart:1e3,direction:"left",duplicated:false,duration:5e3,speed:0,gap:20,pauseOnCycle:false,pauseOnHover:false,startVisible:false}}); -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Exception/Frame.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Exception; 8 | 9 | use InvalidArgumentException; 10 | use Serializable; 11 | 12 | class Frame implements Serializable 13 | { 14 | /** 15 | * @var array 16 | */ 17 | protected $frame; 18 | 19 | /** 20 | * @var string 21 | */ 22 | protected $fileContentsCache; 23 | 24 | /** 25 | * @var array[] 26 | */ 27 | protected $comments = []; 28 | 29 | /** 30 | * @var bool 31 | */ 32 | protected $application; 33 | 34 | /** 35 | * @param array[] 36 | */ 37 | public function __construct(array $frame) 38 | { 39 | $this->frame = $frame; 40 | } 41 | 42 | /** 43 | * @param bool $shortened 44 | * @return string|null 45 | */ 46 | public function getFile($shortened = false) 47 | { 48 | if (empty($this->frame['file'])) { 49 | return null; 50 | } 51 | 52 | $file = $this->frame['file']; 53 | 54 | // Check if this frame occurred within an eval(). 55 | // @todo: This can be made more reliable by checking if we've entered 56 | // eval() in a previous trace, but will need some more work on the upper 57 | // trace collector(s). 58 | if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) { 59 | $file = $this->frame['file'] = $matches[1]; 60 | $this->frame['line'] = (int) $matches[2]; 61 | } 62 | 63 | if ($shortened && is_string($file)) { 64 | // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks. 65 | $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); 66 | if ($dirname !== '/') { 67 | $file = str_replace($dirname, "…", $file); 68 | } 69 | $file = str_replace("/", "/­", $file); 70 | } 71 | 72 | return $file; 73 | } 74 | 75 | /** 76 | * @return int|null 77 | */ 78 | public function getLine() 79 | { 80 | return isset($this->frame['line']) ? $this->frame['line'] : null; 81 | } 82 | 83 | /** 84 | * @return string|null 85 | */ 86 | public function getClass() 87 | { 88 | return isset($this->frame['class']) ? $this->frame['class'] : null; 89 | } 90 | 91 | /** 92 | * @return string|null 93 | */ 94 | public function getFunction() 95 | { 96 | return isset($this->frame['function']) ? $this->frame['function'] : null; 97 | } 98 | 99 | /** 100 | * @return array 101 | */ 102 | public function getArgs() 103 | { 104 | return isset($this->frame['args']) ? (array) $this->frame['args'] : []; 105 | } 106 | 107 | /** 108 | * Returns the full contents of the file for this frame, 109 | * if it's known. 110 | * @return string|null 111 | */ 112 | public function getFileContents() 113 | { 114 | if ($this->fileContentsCache === null && $filePath = $this->getFile()) { 115 | // Leave the stage early when 'Unknown' or '[internal]' is passed 116 | // this would otherwise raise an exception when 117 | // open_basedir is enabled. 118 | if ($filePath === "Unknown" || $filePath === '[internal]') { 119 | return null; 120 | } 121 | 122 | try { 123 | $this->fileContentsCache = file_get_contents($filePath); 124 | } catch (ErrorException $exception) { 125 | // Internal file paths of PHP extensions cannot be opened 126 | } 127 | } 128 | 129 | return $this->fileContentsCache; 130 | } 131 | 132 | /** 133 | * Adds a comment to this frame, that can be received and 134 | * used by other handlers. For example, the PrettyPage handler 135 | * can attach these comments under the code for each frame. 136 | * 137 | * An interesting use for this would be, for example, code analysis 138 | * & annotations. 139 | * 140 | * @param string $comment 141 | * @param string $context Optional string identifying the origin of the comment 142 | */ 143 | public function addComment($comment, $context = 'global') 144 | { 145 | $this->comments[] = [ 146 | 'comment' => $comment, 147 | 'context' => $context, 148 | ]; 149 | } 150 | 151 | /** 152 | * Returns all comments for this frame. Optionally allows 153 | * a filter to only retrieve comments from a specific 154 | * context. 155 | * 156 | * @param string $filter 157 | * @return array[] 158 | */ 159 | public function getComments($filter = null) 160 | { 161 | $comments = $this->comments; 162 | 163 | if ($filter !== null) { 164 | $comments = array_filter($comments, function ($c) use ($filter) { 165 | return $c['context'] == $filter; 166 | }); 167 | } 168 | 169 | return $comments; 170 | } 171 | 172 | /** 173 | * Returns the array containing the raw frame data from which 174 | * this Frame object was built 175 | * 176 | * @return array 177 | */ 178 | public function getRawFrame() 179 | { 180 | return $this->frame; 181 | } 182 | 183 | /** 184 | * Returns the contents of the file for this frame as an 185 | * array of lines, and optionally as a clamped range of lines. 186 | * 187 | * NOTE: lines are 0-indexed 188 | * 189 | * @example 190 | * Get all lines for this file 191 | * $frame->getFileLines(); // => array( 0 => ' '...', ...) 192 | * @example 193 | * Get one line for this file, starting at line 10 (zero-indexed, remember!) 194 | * $frame->getFileLines(9, 1); // array( 9 => '...' ) 195 | * 196 | * @throws InvalidArgumentException if $length is less than or equal to 0 197 | * @param int $start 198 | * @param int $length 199 | * @return string[]|null 200 | */ 201 | public function getFileLines($start = 0, $length = null) 202 | { 203 | if (null !== ($contents = $this->getFileContents())) { 204 | $lines = explode("\n", $contents); 205 | 206 | // Get a subset of lines from $start to $end 207 | if ($length !== null) { 208 | $start = (int) $start; 209 | $length = (int) $length; 210 | if ($start < 0) { 211 | $start = 0; 212 | } 213 | 214 | if ($length <= 0) { 215 | throw new InvalidArgumentException( 216 | "\$length($length) cannot be lower or equal to 0" 217 | ); 218 | } 219 | 220 | $lines = array_slice($lines, $start, $length, true); 221 | } 222 | 223 | return $lines; 224 | } 225 | } 226 | 227 | /** 228 | * Implements the Serializable interface, with special 229 | * steps to also save the existing comments. 230 | * 231 | * @see Serializable::serialize 232 | * @return string 233 | */ 234 | public function serialize() 235 | { 236 | $frame = $this->frame; 237 | if (!empty($this->comments)) { 238 | $frame['_comments'] = $this->comments; 239 | } 240 | 241 | return serialize($frame); 242 | } 243 | 244 | public function __serialize() 245 | { 246 | $frame = $this->frame; 247 | if (!empty($this->comments)) { 248 | $frame['_comments'] = $this->comments; 249 | } 250 | return $frame; 251 | } 252 | 253 | /** 254 | * Unserializes the frame data, while also preserving 255 | * any existing comment data. 256 | * 257 | * @see Serializable::unserialize 258 | * @param string $serializedFrame 259 | */ 260 | public function unserialize($serializedFrame) 261 | { 262 | $frame = unserialize($serializedFrame); 263 | 264 | if (!empty($frame['_comments'])) { 265 | $this->comments = $frame['_comments']; 266 | unset($frame['_comments']); 267 | } 268 | 269 | $this->frame = $frame; 270 | } 271 | 272 | public function __unserialize($frame) 273 | { 274 | if (!empty($frame['_comments'])) { 275 | $this->comments = $frame['_comments']; 276 | unset($frame['_comments']); 277 | } 278 | 279 | $this->frame = $frame; 280 | } 281 | 282 | /** 283 | * Compares Frame against one another 284 | * @param Frame $frame 285 | * @return bool 286 | */ 287 | public function equals(Frame $frame) 288 | { 289 | if (!$this->getFile() || $this->getFile() === 'Unknown' || !$this->getLine()) { 290 | return false; 291 | } 292 | return $frame->getFile() === $this->getFile() && $frame->getLine() === $this->getLine(); 293 | } 294 | 295 | /** 296 | * Returns whether this frame belongs to the application or not. 297 | * 298 | * @return boolean 299 | */ 300 | public function isApplication() 301 | { 302 | return $this->application; 303 | } 304 | 305 | /** 306 | * Mark as an frame belonging to the application. 307 | * 308 | * @param boolean $application 309 | */ 310 | public function setApplication($application) 311 | { 312 | $this->application = $application; 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /core/Views/admin/settings/index.kyaaaa.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/Controllers/AdminCtrl.php: -------------------------------------------------------------------------------- 1 | AdminModel = new AdminModel(); 9 | $this->request = request(); 10 | $this->session = session(); 11 | } 12 | 13 | public function login() { 14 | $data['title'] = 'Login'; 15 | return view('auth/auth', $data); 16 | } 17 | 18 | public function logout() { 19 | $this->session->clear(); 20 | redirectTo(url('login')); 21 | } 22 | 23 | public function auth() { 24 | $email = $this->request->post('email'); 25 | $password = $this->request->post('password'); 26 | $get = $this->AdminModel->get_user_by_email($email); 27 | if (!empty($get)) { 28 | $verifyPassword = password_verify($password, $get[0]->password); 29 | if ($verifyPassword) { 30 | if ($get[0]->roles == '1') { 31 | $sessiondata = [ 32 | 'isAdmin' => TRUE, 33 | 'name' => $get[0]->name, 34 | 'username' => $get[0]->username, 35 | 'email' => $get[0]->email, 36 | ]; 37 | $this->session->set($sessiondata); 38 | return redirectTo(url('dashboard')); 39 | } else { 40 | $this->session->flash('error', 'invalid role'); 41 | return redirectTo(url('login')); 42 | } 43 | 44 | } else { 45 | $this->session->flash('error', 'Password/Email Salah!'); 46 | return redirectTo(url('login')); 47 | } 48 | } else { 49 | $this->session->flash('error', 'Password/Email Salah!'); 50 | return redirectTo(url('login')); 51 | } 52 | } 53 | 54 | public function index() { 55 | $data['title'] = 'Dashboard'; 56 | $data['paid'] = $this->AdminModel->count_paid(); 57 | $data['total'] = $this->AdminModel->count_all(); 58 | $data['profit'] = $this->AdminModel->total_paid_donation(); 59 | $data['donations'] = $this->AdminModel->get_donations(); 60 | $data['users'] = $this->AdminModel->get_users(); 61 | return view('admin/index', $data); 62 | } 63 | 64 | public function settings() { 65 | $data['title'] = 'Settings'; 66 | $data['settings'] = $this->AdminModel->get_settings(); 67 | $data['users'] = $this->AdminModel->get_users(); 68 | return view('admin/settings/index', $data); 69 | } 70 | 71 | public function update_profile() { 72 | $file = $this->request->file('avatar'); 73 | if ($this->request->getFileSize($file) != 0) { 74 | $allowedTypes = [ 75 | 'image/png' => 'png', 76 | 'image/jpeg' => 'jpg' 77 | ]; 78 | if (!$this->request->validate($file, $allowedTypes)) { 79 | $this->session->flash('error', 'File not allowed!'); 80 | redirectTo(url('dashboard/settings')); 81 | } 82 | if ($this->request->getFileSize($file) >= 5) { 83 | $this->session->flash('error', 'Avatar Max Size 5MB'); 84 | redirectTo(url('dashboard/settings')); 85 | } 86 | $path = 'assets/img'; 87 | $newfilename = 'avatar.png'; 88 | $moveFile = $this->request->move($file, $path, $newfilename, true); 89 | } 90 | 91 | $data['name'] = $this->request->post('name'); 92 | $data['username'] = $this->request->post('username'); 93 | $data['email'] = $this->request->post('email'); 94 | if (!empty($this->request->post('password'))) { 95 | $data['password'] = password_hash($this->request->post('password'), PASSWORD_DEFAULT); 96 | } 97 | if (!empty($this->request->post('ig'))) { 98 | $data['ig'] = $this->request->post('ig'); 99 | } 100 | if (!empty($this->request->post('fb'))) { 101 | $data['fb'] = $this->request->post('fb'); 102 | } 103 | if (!empty($this->request->post('twitter'))) { 104 | $data['twitter'] = $this->request->post('twitter'); 105 | } 106 | if (!empty($this->request->post('yt'))) { 107 | $data['yt'] = $this->request->post('yt'); 108 | } 109 | if (!empty($this->request->post('twitch'))) { 110 | $data['twitch'] = $this->request->post('twitch'); 111 | } 112 | if (!empty($this->request->post('github'))) { 113 | $data['github'] = $this->request->post('github'); 114 | } 115 | if (!empty($this->request->post('linkedin'))) { 116 | $data['linkedin'] = $this->request->post('linkedin'); 117 | } 118 | $update = $this->AdminModel->update_profile($data); 119 | if ($update) { 120 | $this->session->flash('success', 'Saved!'); 121 | redirectTo(url('dashboard/settings')); 122 | } else { 123 | $this->session->flash('error', 'Failed!'); 124 | redirectTo(url('dashboard/settings')); 125 | } 126 | } 127 | 128 | public function update_stream() { 129 | $file = $this->request->file('notif'); 130 | if ($this->request->getFileSize($file) != 0) { 131 | $allowedTypes = [ 132 | 'audio/mpeg' => 'mp3' 133 | ]; 134 | if (!$this->request->validate($file, $allowedTypes)) { 135 | $this->session->flash('error', 'File not allowed!'); 136 | redirectTo(url('dashboard/settings')); 137 | } 138 | if ($this->request->getFileSize($file) >= 5) { 139 | $this->session->flash('error', 'Max Size 5MB'); 140 | redirectTo(url('dashboard/settings')); 141 | } 142 | $path = 'assets/notif'; 143 | $newfilename = 'notif.mp3'; 144 | $moveFile = $this->request->move($file, $path, $newfilename, true); 145 | $this->session->flash('success', 'Saved!'); 146 | redirectTo(url('dashboard/settings')); 147 | } else { 148 | $this->session->flash('error', 'No File'); 149 | redirectTo(url('dashboard/settings')); 150 | } 151 | } 152 | 153 | public function update_tripay() { 154 | if (!empty($this->request->post('merchant_code'))) { 155 | $data['merchant_code'] = $this->request->post('merchant_code'); 156 | } else { 157 | $this->session->flash('error', 'Fill the required fields'); 158 | redirectTo(url('dashboard/settings')); 159 | } 160 | if (!empty($this->request->post('merchant_api_key'))) { 161 | $data['merchant_api_key'] = $this->request->post('merchant_api_key'); 162 | } else { 163 | $this->session->flash('error', 'Fill the required fields'); 164 | redirectTo(url('dashboard/settings')); 165 | } 166 | if (!empty($this->request->post('merchant_private_key'))) { 167 | $data['merchant_private_key'] = $this->request->post('merchant_private_key'); 168 | } else { 169 | $this->session->flash('error', 'Fill the required fields'); 170 | redirectTo(url('dashboard/settings')); 171 | } 172 | if (!empty($this->request->post('endpoint'))) { 173 | $data['endpoint'] = $this->request->post('endpoint'); 174 | } else { 175 | $this->session->flash('error', 'Fill the required fields'); 176 | redirectTo(url('dashboard/settings')); 177 | } 178 | $update = $this->AdminModel->update_settings($data); 179 | if ($update) { 180 | $this->session->flash('success', 'Saved!'); 181 | redirectTo(url('dashboard/settings')); 182 | } else { 183 | $this->session->flash('error', 'Failed!'); 184 | redirectTo(url('dashboard/settings')); 185 | } 186 | } 187 | 188 | public function update_pusher() { 189 | if (!empty($this->request->post('pusher_app_id'))) { 190 | $data['pusher_app_id'] = $this->request->post('pusher_app_id'); 191 | } else { 192 | $this->session->flash('error', 'Fill the required fields'); 193 | redirectTo(url('dashboard/settings')); 194 | } 195 | if (!empty($this->request->post('pusher_key'))) { 196 | $data['pusher_key'] = $this->request->post('pusher_key'); 197 | } else { 198 | $this->session->flash('error', 'Fill the required fields'); 199 | redirectTo(url('dashboard/settings')); 200 | } 201 | if (!empty($this->request->post('pusher_secret'))) { 202 | $data['pusher_secret'] = $this->request->post('pusher_secret'); 203 | } else { 204 | $this->session->flash('error', 'Fill the required fields'); 205 | redirectTo(url('dashboard/settings')); 206 | } 207 | if (!empty($this->request->post('pusher_cluster'))) { 208 | $data['pusher_cluster'] = $this->request->post('pusher_cluster'); 209 | } else { 210 | $this->session->flash('error', 'Fill the required fields'); 211 | redirectTo(url('dashboard/settings')); 212 | } 213 | $update = $this->AdminModel->update_settings($data); 214 | if ($update) { 215 | $this->session->flash('success', 'Saved!'); 216 | redirectTo(url('dashboard/settings')); 217 | } else { 218 | $this->session->flash('error', 'Failed!'); 219 | redirectTo(url('dashboard/settings')); 220 | } 221 | } 222 | 223 | public function test_notification() { 224 | $loadpusher = new \Core\Conf\Kyaaaa\Tripay(); // correct 225 | $pusher = $loadpusher->pusher(); 226 | $push['name'] = 'Seseorang'; 227 | $push['amount'] = 'Rp 1.000.000.000'; 228 | $push['jumlah'] = '1000000000'; 229 | $push['msgs'] = 'Ini adalah test, notifikasi donasi siap digunakan!'; 230 | 231 | $pusher->trigger('my_stream', 'donate_event', $push); 232 | echo json_encode([ 233 | 'success' => true, 234 | ]); 235 | exit; 236 | } 237 | 238 | } -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Exception/Inspector.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace Core\Conf\Kyaaaa\Handler\Exception; 8 | 9 | use Core\Conf\Kyaaaa\Handler\Util\Misc; 10 | 11 | class Inspector 12 | { 13 | /** 14 | * @var \Throwable 15 | */ 16 | private $exception; 17 | 18 | /** 19 | * @var \Core\Conf\Kyaaaa\Handler\Exception\FrameCollection 20 | */ 21 | private $frames; 22 | 23 | /** 24 | * @var \Core\Conf\Kyaaaa\Handler\Exception\Inspector 25 | */ 26 | private $previousExceptionInspector; 27 | 28 | /** 29 | * @var \Throwable[] 30 | */ 31 | private $previousExceptions; 32 | 33 | /** 34 | * @param \Throwable $exception The exception to inspect 35 | */ 36 | public function __construct($exception) 37 | { 38 | $this->exception = $exception; 39 | } 40 | 41 | /** 42 | * @return \Throwable 43 | */ 44 | public function getException() 45 | { 46 | return $this->exception; 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function getExceptionName() 53 | { 54 | return get_class($this->exception); 55 | } 56 | 57 | /** 58 | * @return string 59 | */ 60 | public function getExceptionMessage() 61 | { 62 | return $this->extractDocrefUrl($this->exception->getMessage())['message']; 63 | } 64 | 65 | /** 66 | * @return string[] 67 | */ 68 | public function getPreviousExceptionMessages() 69 | { 70 | return array_map(function ($prev) { 71 | /** @var \Throwable $prev */ 72 | return $this->extractDocrefUrl($prev->getMessage())['message']; 73 | }, $this->getPreviousExceptions()); 74 | } 75 | 76 | /** 77 | * @return int[] 78 | */ 79 | public function getPreviousExceptionCodes() 80 | { 81 | return array_map(function ($prev) { 82 | /** @var \Throwable $prev */ 83 | return $prev->getCode(); 84 | }, $this->getPreviousExceptions()); 85 | } 86 | 87 | /** 88 | * Returns a url to the php-manual related to the underlying error - when available. 89 | * 90 | * @return string|null 91 | */ 92 | public function getExceptionDocrefUrl() 93 | { 94 | return $this->extractDocrefUrl($this->exception->getMessage())['url']; 95 | } 96 | 97 | private function extractDocrefUrl($message) 98 | { 99 | $docref = [ 100 | 'message' => $message, 101 | 'url' => null, 102 | ]; 103 | 104 | // php embbeds urls to the manual into the Exception message with the following ini-settings defined 105 | // http://php.net/manual/en/errorfunc.configuration.php#ini.docref-root 106 | if (!ini_get('html_errors') || !ini_get('docref_root')) { 107 | return $docref; 108 | } 109 | 110 | $pattern = "/\[(?:[^<]+)<\/a>\]/"; 111 | if (preg_match($pattern, $message, $matches)) { 112 | // -> strip those automatically generated links from the exception message 113 | $docref['message'] = preg_replace($pattern, '', $message, 1); 114 | $docref['url'] = $matches[1]; 115 | } 116 | 117 | return $docref; 118 | } 119 | 120 | /** 121 | * Does the wrapped Exception has a previous Exception? 122 | * @return bool 123 | */ 124 | public function hasPreviousException() 125 | { 126 | return $this->previousExceptionInspector || $this->exception->getPrevious(); 127 | } 128 | 129 | /** 130 | * Returns an Inspector for a previous Exception, if any. 131 | * @todo Clean this up a bit, cache stuff a bit better. 132 | * @return Inspector 133 | */ 134 | public function getPreviousExceptionInspector() 135 | { 136 | if ($this->previousExceptionInspector === null) { 137 | $previousException = $this->exception->getPrevious(); 138 | 139 | if ($previousException) { 140 | $this->previousExceptionInspector = new Inspector($previousException); 141 | } 142 | } 143 | 144 | return $this->previousExceptionInspector; 145 | } 146 | 147 | 148 | /** 149 | * Returns an array of all previous exceptions for this inspector's exception 150 | * @return \Throwable[] 151 | */ 152 | public function getPreviousExceptions() 153 | { 154 | if ($this->previousExceptions === null) { 155 | $this->previousExceptions = []; 156 | 157 | $prev = $this->exception->getPrevious(); 158 | while ($prev !== null) { 159 | $this->previousExceptions[] = $prev; 160 | $prev = $prev->getPrevious(); 161 | } 162 | } 163 | 164 | return $this->previousExceptions; 165 | } 166 | 167 | /** 168 | * Returns an iterator for the inspected exception's 169 | * frames. 170 | * @return \Core\Conf\Kyaaaa\Handler\Exception\FrameCollection 171 | */ 172 | public function getFrames() 173 | { 174 | if ($this->frames === null) { 175 | $frames = $this->getTrace($this->exception); 176 | 177 | // Fill empty line/file info for call_user_func_array usages (PHP Bug #44428) 178 | foreach ($frames as $k => $frame) { 179 | if (empty($frame['file'])) { 180 | // Default values when file and line are missing 181 | $file = '[internal]'; 182 | $line = 0; 183 | 184 | $next_frame = !empty($frames[$k + 1]) ? $frames[$k + 1] : []; 185 | 186 | if ($this->isValidNextFrame($next_frame)) { 187 | $file = $next_frame['file']; 188 | $line = $next_frame['line']; 189 | } 190 | 191 | $frames[$k]['file'] = $file; 192 | $frames[$k]['line'] = $line; 193 | } 194 | } 195 | 196 | // Find latest non-error handling frame index ($i) used to remove error handling frames 197 | $i = 0; 198 | foreach ($frames as $k => $frame) { 199 | if ($frame['file'] == $this->exception->getFile() && $frame['line'] == $this->exception->getLine()) { 200 | $i = $k; 201 | } 202 | } 203 | 204 | // Remove error handling frames 205 | if ($i > 0) { 206 | array_splice($frames, 0, $i); 207 | } 208 | 209 | $firstFrame = $this->getFrameFromException($this->exception); 210 | array_unshift($frames, $firstFrame); 211 | 212 | $this->frames = new FrameCollection($frames); 213 | 214 | if ($previousInspector = $this->getPreviousExceptionInspector()) { 215 | // Keep outer frame on top of the inner one 216 | $outerFrames = $this->frames; 217 | $newFrames = clone $previousInspector->getFrames(); 218 | // I assume it will always be set, but let's be safe 219 | if (isset($newFrames[0])) { 220 | $newFrames[0]->addComment( 221 | $previousInspector->getExceptionMessage(), 222 | 'Exception message:' 223 | ); 224 | } 225 | $newFrames->prependFrames($outerFrames->topDiff($newFrames)); 226 | $this->frames = $newFrames; 227 | } 228 | } 229 | 230 | return $this->frames; 231 | } 232 | 233 | /** 234 | * Gets the backtrace from an exception. 235 | * 236 | * If xdebug is installed 237 | * 238 | * @param \Throwable $e 239 | * @return array 240 | */ 241 | protected function getTrace($e) 242 | { 243 | $traces = $e->getTrace(); 244 | 245 | // Get trace from xdebug if enabled, failure exceptions only trace to the shutdown handler by default 246 | if (!$e instanceof \ErrorException) { 247 | return $traces; 248 | } 249 | 250 | if (!Misc::isLevelFatal($e->getSeverity())) { 251 | return $traces; 252 | } 253 | 254 | if (!extension_loaded('xdebug') || !function_exists('xdebug_is_enabled') || !xdebug_is_enabled()) { 255 | return $traces; 256 | } 257 | 258 | // Use xdebug to get the full stack trace and remove the shutdown handler stack trace 259 | $stack = array_reverse(xdebug_get_function_stack()); 260 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); 261 | $traces = array_diff_key($stack, $trace); 262 | 263 | return $traces; 264 | } 265 | 266 | /** 267 | * Given an exception, generates an array in the format 268 | * generated by Exception::getTrace() 269 | * @param \Throwable $exception 270 | * @return array 271 | */ 272 | protected function getFrameFromException($exception) 273 | { 274 | return [ 275 | 'file' => $exception->getFile(), 276 | 'line' => $exception->getLine(), 277 | 'class' => get_class($exception), 278 | 'args' => [ 279 | $exception->getMessage(), 280 | ], 281 | ]; 282 | } 283 | 284 | /** 285 | * Given an error, generates an array in the format 286 | * generated by ErrorException 287 | * @param ErrorException $exception 288 | * @return array 289 | */ 290 | protected function getFrameFromError(ErrorException $exception) 291 | { 292 | return [ 293 | 'file' => $exception->getFile(), 294 | 'line' => $exception->getLine(), 295 | 'class' => null, 296 | 'args' => [], 297 | ]; 298 | } 299 | 300 | /** 301 | * Determine if the frame can be used to fill in previous frame's missing info 302 | * happens for call_user_func and call_user_func_array usages (PHP Bug #44428) 303 | * 304 | * @param array $frame 305 | * @return bool 306 | */ 307 | protected function isValidNextFrame(array $frame) 308 | { 309 | if (empty($frame['file'])) { 310 | return false; 311 | } 312 | 313 | if (empty($frame['line'])) { 314 | return false; 315 | } 316 | 317 | if (empty($frame['function']) || !stristr($frame['function'], 'call_user_func')) { 318 | return false; 319 | } 320 | 321 | return true; 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /core/Conf/Kyaaaa/Handler/Handler/PlainTextHandler.php: -------------------------------------------------------------------------------- 1 | 5 | * Plaintext handler for command line and logs. 6 | * @author Pierre-Yves Landuré 7 | */ 8 | 9 | namespace Core\Conf\Kyaaaa\Handler\Handler; 10 | 11 | use InvalidArgumentException; 12 | use Psr\Log\LoggerInterface; 13 | use Core\Conf\Kyaaaa\Handler\Exception\Frame; 14 | 15 | /** 16 | * Handler outputing plaintext error messages. Can be used 17 | * directly, or will be instantiated automagically by Core\App\Kyaaaa\Handler\Run 18 | * if passed to Run::pushHandler 19 | */ 20 | class PlainTextHandler extends Handler 21 | { 22 | const VAR_DUMP_PREFIX = ' | '; 23 | 24 | /** 25 | * @var \Psr\Log\LoggerInterface 26 | */ 27 | protected $logger; 28 | 29 | /** 30 | * @var callable 31 | */ 32 | protected $dumper; 33 | 34 | /** 35 | * @var bool 36 | */ 37 | private $addTraceToOutput = true; 38 | 39 | /** 40 | * @var bool|integer 41 | */ 42 | private $addTraceFunctionArgsToOutput = false; 43 | 44 | /** 45 | * @var integer 46 | */ 47 | private $traceFunctionArgsOutputLimit = 1024; 48 | 49 | /** 50 | * @var bool 51 | */ 52 | private $addPreviousToOutput = true; 53 | 54 | /** 55 | * @var bool 56 | */ 57 | private $loggerOnly = false; 58 | 59 | /** 60 | * Constructor. 61 | * @throws InvalidArgumentException If argument is not null or a LoggerInterface 62 | * @param \Psr\Log\LoggerInterface|null $logger 63 | */ 64 | public function __construct($logger = null) 65 | { 66 | $this->setLogger($logger); 67 | } 68 | 69 | /** 70 | * Set the output logger interface. 71 | * @throws InvalidArgumentException If argument is not null or a LoggerInterface 72 | * @param \Psr\Log\LoggerInterface|null $logger 73 | */ 74 | public function setLogger($logger = null) 75 | { 76 | if (! (is_null($logger) 77 | || $logger instanceof LoggerInterface)) { 78 | throw new InvalidArgumentException( 79 | 'Argument to ' . __METHOD__ . 80 | " must be a valid Logger Interface (aka. Monolog), " . 81 | get_class($logger) . ' given.' 82 | ); 83 | } 84 | 85 | $this->logger = $logger; 86 | } 87 | 88 | /** 89 | * @return \Psr\Log\LoggerInterface|null 90 | */ 91 | public function getLogger() 92 | { 93 | return $this->logger; 94 | } 95 | 96 | /** 97 | * Set var dumper callback function. 98 | * 99 | * @param callable $dumper 100 | * @return static 101 | */ 102 | public function setDumper(callable $dumper) 103 | { 104 | $this->dumper = $dumper; 105 | return $this; 106 | } 107 | 108 | /** 109 | * Add error trace to output. 110 | * @param bool|null $addTraceToOutput 111 | * @return bool|static 112 | */ 113 | public function addTraceToOutput($addTraceToOutput = null) 114 | { 115 | if (func_num_args() == 0) { 116 | return $this->addTraceToOutput; 117 | } 118 | 119 | $this->addTraceToOutput = (bool) $addTraceToOutput; 120 | return $this; 121 | } 122 | 123 | /** 124 | * Add previous exceptions to output. 125 | * @param bool|null $addPreviousToOutput 126 | * @return bool|static 127 | */ 128 | public function addPreviousToOutput($addPreviousToOutput = null) 129 | { 130 | if (func_num_args() == 0) { 131 | return $this->addPreviousToOutput; 132 | } 133 | 134 | $this->addPreviousToOutput = (bool) $addPreviousToOutput; 135 | return $this; 136 | } 137 | 138 | /** 139 | * Add error trace function arguments to output. 140 | * Set to True for all frame args, or integer for the n first frame args. 141 | * @param bool|integer|null $addTraceFunctionArgsToOutput 142 | * @return static|bool|integer 143 | */ 144 | public function addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null) 145 | { 146 | if (func_num_args() == 0) { 147 | return $this->addTraceFunctionArgsToOutput; 148 | } 149 | 150 | if (! is_integer($addTraceFunctionArgsToOutput)) { 151 | $this->addTraceFunctionArgsToOutput = (bool) $addTraceFunctionArgsToOutput; 152 | } else { 153 | $this->addTraceFunctionArgsToOutput = $addTraceFunctionArgsToOutput; 154 | } 155 | return $this; 156 | } 157 | 158 | /** 159 | * Set the size limit in bytes of frame arguments var_dump output. 160 | * If the limit is reached, the var_dump output is discarded. 161 | * Prevent memory limit errors. 162 | * @var integer 163 | * @return static 164 | */ 165 | public function setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit) 166 | { 167 | $this->traceFunctionArgsOutputLimit = (integer) $traceFunctionArgsOutputLimit; 168 | return $this; 169 | } 170 | 171 | /** 172 | * Create plain text response and return it as a string 173 | * @return string 174 | */ 175 | public function generateResponse() 176 | { 177 | $exception = $this->getException(); 178 | $message = $this->getExceptionOutput($exception); 179 | 180 | if ($this->addPreviousToOutput) { 181 | $previous = $exception->getPrevious(); 182 | while ($previous) { 183 | $message .= "\n\nCaused by\n" . $this->getExceptionOutput($previous); 184 | $previous = $previous->getPrevious(); 185 | } 186 | } 187 | 188 | 189 | return $message . $this->getTraceOutput() . "\n"; 190 | } 191 | 192 | /** 193 | * Get the size limit in bytes of frame arguments var_dump output. 194 | * If the limit is reached, the var_dump output is discarded. 195 | * Prevent memory limit errors. 196 | * @return integer 197 | */ 198 | public function getTraceFunctionArgsOutputLimit() 199 | { 200 | return $this->traceFunctionArgsOutputLimit; 201 | } 202 | 203 | /** 204 | * Only output to logger. 205 | * @param bool|null $loggerOnly 206 | * @return static|bool 207 | */ 208 | public function loggerOnly($loggerOnly = null) 209 | { 210 | if (func_num_args() == 0) { 211 | return $this->loggerOnly; 212 | } 213 | 214 | $this->loggerOnly = (bool) $loggerOnly; 215 | return $this; 216 | } 217 | 218 | /** 219 | * Test if handler can output to stdout. 220 | * @return bool 221 | */ 222 | private function canOutput() 223 | { 224 | return !$this->loggerOnly(); 225 | } 226 | 227 | /** 228 | * Get the frame args var_dump. 229 | * @param \Core\Conf\Kyaaaa\Handler\Exception\Frame $frame [description] 230 | * @param integer $line [description] 231 | * @return string 232 | */ 233 | private function getFrameArgsOutput(Frame $frame, $line) 234 | { 235 | if ($this->addTraceFunctionArgsToOutput() === false 236 | || $this->addTraceFunctionArgsToOutput() < $line) { 237 | return ''; 238 | } 239 | 240 | // Dump the arguments: 241 | ob_start(); 242 | $this->dump($frame->getArgs()); 243 | if (ob_get_length() > $this->getTraceFunctionArgsOutputLimit()) { 244 | // The argument var_dump is to big. 245 | // Discarded to limit memory usage. 246 | ob_clean(); 247 | return sprintf( 248 | "\n%sArguments dump length greater than %d Bytes. Discarded.", 249 | self::VAR_DUMP_PREFIX, 250 | $this->getTraceFunctionArgsOutputLimit() 251 | ); 252 | } 253 | 254 | return sprintf( 255 | "\n%s", 256 | preg_replace('/^/m', self::VAR_DUMP_PREFIX, ob_get_clean()) 257 | ); 258 | } 259 | 260 | /** 261 | * Dump variable. 262 | * 263 | * @param mixed $var 264 | * @return void 265 | */ 266 | protected function dump($var) 267 | { 268 | if ($this->dumper) { 269 | call_user_func($this->dumper, $var); 270 | } else { 271 | var_dump($var); 272 | } 273 | } 274 | 275 | /** 276 | * Get the exception trace as plain text. 277 | * @return string 278 | */ 279 | private function getTraceOutput() 280 | { 281 | if (! $this->addTraceToOutput()) { 282 | return ''; 283 | } 284 | $inspector = $this->getInspector(); 285 | $frames = $inspector->getFrames(); 286 | 287 | $response = "\nStack trace:"; 288 | 289 | $line = 1; 290 | foreach ($frames as $frame) { 291 | /** @var Frame $frame */ 292 | $class = $frame->getClass(); 293 | 294 | $template = "\n%3d. %s->%s() %s:%d%s"; 295 | if (! $class) { 296 | // Remove method arrow (->) from output. 297 | $template = "\n%3d. %s%s() %s:%d%s"; 298 | } 299 | 300 | $response .= sprintf( 301 | $template, 302 | $line, 303 | $class, 304 | $frame->getFunction(), 305 | $frame->getFile(), 306 | $frame->getLine(), 307 | $this->getFrameArgsOutput($frame, $line) 308 | ); 309 | 310 | $line++; 311 | } 312 | 313 | return $response; 314 | } 315 | 316 | /** 317 | * Get the exception as plain text. 318 | * @param \Throwable $exception 319 | * @return string 320 | */ 321 | private function getExceptionOutput($exception) 322 | { 323 | return sprintf( 324 | "%s: %s in file %s on line %d", 325 | get_class($exception), 326 | $exception->getMessage(), 327 | $exception->getFile(), 328 | $exception->getLine() 329 | ); 330 | } 331 | 332 | /** 333 | * @return int 334 | */ 335 | public function handle() 336 | { 337 | $response = $this->generateResponse(); 338 | 339 | if ($this->getLogger()) { 340 | $this->getLogger()->error($response); 341 | } 342 | 343 | if (! $this->canOutput()) { 344 | return Handler::DONE; 345 | } 346 | 347 | echo $response; 348 | 349 | return Handler::QUIT; 350 | } 351 | 352 | /** 353 | * @return string 354 | */ 355 | public function contentType() 356 | { 357 | return 'text/plain'; 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /public/assets/js/anime.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2017 Julian Garnier 3 | Released under the MIT license 4 | */ 5 | var $jscomp$this=this; 6 | (function(v,p){"function"===typeof define&&define.amd?define([],p):"object"===typeof module&&module.exports?module.exports=p():v.anime=p()})(this,function(){function v(a){if(!g.col(a))try{return document.querySelectorAll(a)}catch(b){}}function p(a){return a.reduce(function(a,d){return a.concat(g.arr(d)?p(d):d)},[])}function w(a){if(g.arr(a))return a;g.str(a)&&(a=v(a)||a);return a instanceof NodeList||a instanceof HTMLCollection?[].slice.call(a):[a]}function F(a,b){return a.some(function(a){return a===b})} 7 | function A(a){var b={},d;for(d in a)b[d]=a[d];return b}function G(a,b){var d=A(a),c;for(c in a)d[c]=b.hasOwnProperty(c)?b[c]:a[c];return d}function B(a,b){var d=A(a),c;for(c in b)d[c]=g.und(a[c])?b[c]:a[c];return d}function S(a){a=a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,function(a,b,d,h){return b+b+d+d+h+h});var b=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);a=parseInt(b[1],16);var d=parseInt(b[2],16),b=parseInt(b[3],16);return"rgb("+a+","+d+","+b+")"}function T(a){function b(a,b,c){0> 8 | c&&(c+=1);1c?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var d=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a);a=parseInt(d[1])/360;var c=parseInt(d[2])/100,d=parseInt(d[3])/100;if(0==c)c=d=a=d;else{var e=.5>d?d*(1+c):d+c-d*c,l=2*d-e,c=b(l,e,a+1/3),d=b(l,e,a);a=b(l,e,a-1/3)}return"rgb("+255*c+","+255*d+","+255*a+")"}function x(a){if(a=/([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|pc|vw|vh|deg|rad|turn)?/.exec(a))return a[2]}function U(a){if(-1=f.currentTime)for(var u=0;ul&&r=n&&(f.began=!0,e("begin")),e("run")):(r<=l&&0!==P&&(c(0),q&&g()),r>=h&&P!==h&&(c(h),q||g()));a>=h&&(f.remaining?(t=m,"alternate"===f.direction&&(f.reversed=!f.reversed)):(f.pause(),"Promise"in window&&(Q(),R=b()),f.completed||(f.completed=!0,e("complete"))), 19 | k=0);e("update")}a=void 0===a?{}:a;var m,t,k=0,Q=null,R=b(),f=fa(a);f.reset=function(){var a=f.direction,b=f.loop;f.currentTime=0;f.progress=0;f.paused=!0;f.began=!1;f.completed=!1;f.reversed="reverse"===a;f.remaining="alternate"===a&&1===b?2:b;for(a=f.children.length;a--;)b=f.children[a],b.seek(b.offset),b.reset()};f.tick=function(a){m=a;t||(t=m);h((k+m-t)*n.speed)};f.seek=function(a){h(d(a))};f.pause=function(){var a=q.indexOf(f);-1=b&&0<=c&&1>=c){var g=new Float32Array(11);if(b!==d||c!==e)for(var h=0;11>h;++h)g[h]=a(.1*h,b,c);return function(h){if(b===d&&c===e)return h;if(0===h)return 0;if(1===h)return 1;for(var m=0,k=1;10!==k&&g[k]<=h;++k)m+=.1;--k;var k=m+(h-g[k])/(g[k+1]-g[k])*.1,l=3*(1-3*c+3*b)*k*k+2*(3*c-6*b)*k+3*b;if(.001<=l){for(m=0;4>m;++m){l=3*(1-3*c+3*b)*k*k+2*(3*c-6*b)*k+3*b;if(0===l)break; 23 | var n=a(k,b,c)-h,k=k-n/l}h=k}else if(0===l)h=k;else{var k=m,m=m+.1,f=0;do n=k+(m-k)/2,l=a(n,b,c)-h,0++f);h=n}return a(h,d,e)}}}}(),N=function(){function a(a,b){return 0===a||1===a?a:-Math.pow(2,10*(a-1))*Math.sin(2*(a-1-b/(2*Math.PI)*Math.asin(1))*Math.PI/b)}var b="Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "),d={In:[[.55,.085,.68,.53],[.55,.055,.675,.19],[.895,.03,.685,.22],[.755,.05,.855,.06],[.47,0,.745,.715],[.95,.05,.795,.035],[.6,.04,.98, 24 | .335],[.6,-.28,.735,.045],a],Out:[[.25,.46,.45,.94],[.215,.61,.355,1],[.165,.84,.44,1],[.23,1,.32,1],[.39,.575,.565,1],[.19,1,.22,1],[.075,.82,.165,1],[.175,.885,.32,1.275],function(b,c){return 1-a(1-b,c)}],InOut:[[.455,.03,.515,.955],[.645,.045,.355,1],[.77,0,.175,1],[.86,0,.07,1],[.445,.05,.55,.95],[1,0,0,1],[.785,.135,.15,.86],[.68,-.55,.265,1.55],function(b,c){return.5>b?a(2*b,c)/2:1-a(-2*b+2,c)/2}]},c={linear:y(.25,.25,.75,.75)},e={},l;for(l in d)e.type=l,d[e.type].forEach(function(a){return function(d, 25 | e){c["ease"+a.type+b[e]]=g.fnc(d)?d:y.apply($jscomp$this,d)}}(e)),e={type:e.type};return c}(),ia={css:function(a,b,d){return a.style[b]=d},attribute:function(a,b,d){return a.setAttribute(b,d)},object:function(a,b,d){return a[b]=d},transform:function(a,b,d,c,e){c[e]||(c[e]=[]);c[e].push(b+"("+d+")")}},q=[],z=0,ja=function(){function a(){z=requestAnimationFrame(b)}function b(b){var c=q.length;if(c){for(var d=0;dc&&(b.duration=a.duration);a.began=!0;b.children.push(a)});b.reset();b.seek(0);b.autoplay&&b.restart();return b};return b};n.random=function(a,b){return Math.floor(Math.random()*(b-a+1))+a};return n}); --------------------------------------------------------------------------------