├── README.md ├── autoexit.js ├── autoexit_example.js ├── both_example.js ├── my_enginx_config ├── README.txt ├── etc │ ├── init.d │ │ └── php-fcgi │ └── nginx │ │ ├── fastcgi_params │ │ ├── more_complex_example.txt │ │ └── sites-enabled │ │ └── default └── var │ └── www │ └── nginx-default │ ├── 50x.html │ ├── index.html │ ├── log.html │ ├── log.php │ ├── moadmin.php │ └── reload.html ├── nodejs.conf └── nodejs.sh /README.md: -------------------------------------------------------------------------------- 1 | # What is node.js auto restart 2 | It is a set of examples and a module with common problems solved. 3 | It allows easy development and stable production. 4 | 5 | - Run on boot: 6 | To make your program run automaticaly on boot with Upsrart(you need to configure a .sh file and a .conf file) 7 | - Auto restart: 8 | autoexit module to watch all .js files if they have been changed and to restart nodejs. 9 | - A description of how to make your program crash proof from javascript errors. (segfaults still crash) 10 | - Auto reload a module: 11 | makes sense for fast development of slow loading app, 12 | 13 | "http://github.com/shimondoodkin/node-hot-reload":http://github.com/shimondoodkin/node-hot-reload. 14 | 15 | ## How to use nodejs auto restart: 16 | Copy `nodejs.sh` and `autoexit.js` to root folder of your application 17 | for example to `/var/www`. Copying of `autoexit.js` is optional and it can be included from deps folder 18 | 19 | ### Add to your script at top: 20 | require.paths.unshift(__dirname); //make local paths accessible 21 | 22 | ### And to your script at end: 23 | 24 | // exit if any js file or template file is changed. 25 | // it is ok because this script encapsualated in a batch while(true); 26 | // so it runs again after it exits. 27 | var autoexit_watch=require('autoexit').watch; 28 | // 29 | var on_autoexit=function (filename) { } // if it returns false it means to ignore exit this time; 30 | autoexit_watch(__dirname,".js", on_autoexit); 31 | //autoexit_watch(__dirname+"/templates",".html", on_autoexit); 32 | 33 | 34 | 35 | ### You might want to use: `try-catch` that will make your applicaiton not crash on errors 36 | try 37 | { 38 | //your code 39 | } 40 | catch(e) 41 | { 42 | console.log(e.stack) 43 | } 44 | 45 | Also after serving one sucsessful request (application is fully loaded) I add an on error error handler: 46 | 47 | if(!app_loaded) 48 | { 49 | process.on('uncaughtException', function (err) { 50 | console.log('Caught exception: ' + err.stack); 51 | }); 52 | app_loaded=true; 53 | } 54 | 55 | As i like it, I want it to crash on load errors and exit the application but not on application errors. 56 | 57 | ### Example: 58 | require.paths.unshift(__dirname); //make local paths accessible 59 | 60 | var http = require('http'); 61 | var app_loaded=false; 62 | 63 | http.createServer(function (req, res) { 64 | 65 | if(!app_loaded) 66 | { 67 | process.on('uncaughtException', function (err) { 68 | console.log('Caught exception: ' + err.stack); 69 | }); 70 | app_loaded=true; 71 | } 72 | 73 | try 74 | { 75 | 76 | res.writeHead(200, {'Content-Type': 'text/plain'}); 77 | res.end('Hello World\n'); 78 | 79 | } 80 | catch(e) 81 | { 82 | console.log(e.stack); 83 | } 84 | 85 | }).listen(8124); 86 | console.log('Server running at http://127.0.0.1:8124/'); 87 | 88 | // exit if any js file or template file is changed. 89 | // it is ok because this script encapsualated in a batch while(true); 90 | // so it runs again after it exits. 91 | var autoexit_watch=require('autoexit').watch; 92 | // 93 | var on_autoexit=function () { console.log('bye bye'); } 94 | autoexit_watch(__dirname,".js", on_autoexit); 95 | //autoexit_watch(__dirname+"/templates",".html", on_autoexit); 96 | 97 | 98 | 99 | 100 | ### Edit nodejs.sh 101 | Edit `nodejs.sh` to match to your server.js filename. 102 | 103 | 104 | ### To launch nodejs you type 105 | cd /var/www 106 | ./nodejs.sh 107 | 108 | ### To make it work with upstart - make it run on boot 109 | Copy `nodejs.conf` to `/etc/init/` 110 | and modify it to point to nodejs.sh 111 | 112 | Upstart is originated in Ubuntu linux. if your linux does not have upstart. An option for you migh be to install upstart. 113 | 114 | ### To use upstart you type : 115 | 116 | [command] + [init filename without conf extention] 117 | 118 | start nodejs 119 | stop nodejs 120 | restrt nodejs 121 | 122 | ### When i start to develop I connect to the server with ssh and run: 123 | 124 | stop nodejs 125 | cd /var/www 126 | ./nodejs.sh 127 | 128 | 129 | Then I will start to see application output and errors on the screen 130 | If I want to stop the server I press `Control + C` 131 | and the script stops. 132 | note: the output will not bet visible if logging is configured in node.sh. the output will go to log. 133 | 134 | ### Nginx? 135 | Yes I also use Nginx as front. (but it is not required). I use it 136 | to let me in the future to change and integrate different servers seemlessly. 137 | It is basicly: nginx<->nodejs as an upstream. 138 | also i have added php-cgi to nginx to use +Rock mongo+ - a mongodb db editor. 139 | also i've added a log.php , log file viewer so don't even need ssh. 140 | 141 | 142 | ### Multi Process 143 | you can put nginx or haproxy as a front and create several .conf files for the upstart. 144 | 145 | in each you modify the execution line to contain port number ex.: 146 | 147 | in the nodejs1.conf 148 | exec sudo -u www-data /bin/bash /var/www/nodejs-mongodb-app/nodejs.sh 8001 149 | in the nodejs2.conf 150 | exec sudo -u www-data /bin/bash /var/www/nodejs-mongodb-app/nodejs.sh 8002 151 | 152 | and make port as an argument to your server.js. 153 | //http.createServer(server_handler_function).listen(process.argv[2]||8001); 154 | //see http://nodejs.org/api.html#process-argv-58 155 | //process.argv.forEach(function (val, index, array) { 156 | // console.log(index + ': ' + val); 157 | //}); 158 | 159 | To achive best performance. it was found by testing (during development of twisted and nginx) that the number of processors should much the number of cores not more not lest. 160 | 161 | ### the idea behind the architecture 162 | the idea is to add an extra level of fail-safety by using a stable system shell script to restart node instead of node itself. 163 | -------------------------------------------------------------------------------- /autoexit.js: -------------------------------------------------------------------------------- 1 | //license: public domain 2 | // by Shimon Doodkin 3 | 4 | //example: 5 | 6 | // // exit if any js file or template file is changed. 7 | // // this script encapsualated in a batch while(true); so it runs again after exit. 8 | // var autoexit_watch=require('deps/nodejs-autorestart/autoexit').watch; 9 | // autoexit_watch(__dirname,".js"); 10 | // autoexit_watch(__dirname+"/templates",".html"); 11 | 12 | 13 | //////// begin - auto exit on js files changed ////////////////////////// 14 | // run this file with the kind of the folowing shell script one liner command: 15 | // while true; do node server.js; done; 16 | // 17 | 18 | var fs = require('fs'); // allaws to open files 19 | var sys = require('sys'); // allows to print errors to command line 20 | this.restarted=false; 21 | var that=this; 22 | 23 | function watch(parse_file_list_dirname,extention,callback) { 24 | var restart_server = function(filename) 25 | { 26 | if(that.restarted) return; 27 | that.restarted=true; 28 | var ignore=false; 29 | var callbackresult=true;; 30 | if(callback)callbackresult=callback(filename); 31 | ignore=(callbackresult===false); 32 | if(!ignore) 33 | { 34 | sys.puts((new Date).toTimeString()+' change discovered, restarting server. the file was: '+filename); 35 | process.exit(); 36 | } 37 | else 38 | that.restarted=false; 39 | } 40 | 41 | var parse_file_list1 = function(dir, files, extention) 42 | { 43 | for (var i=0;i /etc/php5/conf.d/mongo.ini 71 | -------------------------------------------------------------------------------- /my_enginx_config/etc/init.d/php-fcgi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ######################### 4 | # 5 | # to install this script first copy it to /etc/init.d 6 | # then from /etc/init.d folder run 7 | # 8 | # update-rc.d php-fcgi defaults 9 | # 10 | # this command will creata all the /etc/rc1.d .. /etc/rc5.d symbolic links 11 | # 12 | ########################### 13 | 14 | BIND=127.0.0.1:9000 15 | USER=www-data 16 | #children was 15 17 | #generaly i dont need php 18 | PHP_FCGI_CHILDREN=2 19 | PHP_FCGI_MAX_REQUESTS=1000 20 | 21 | PHP_CGI=/usr/bin/php-cgi 22 | PHP_CGI_NAME=`basename $PHP_CGI` 23 | PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND" 24 | RETVAL=0 25 | 26 | start() { 27 | echo -n "Starting PHP FastCGI: " 28 | start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS 29 | RETVAL=$? 30 | echo "$PHP_CGI_NAME." 31 | } 32 | stop() { 33 | echo -n "Stopping PHP FastCGI: " 34 | killall -q -w -u $USER $PHP_CGI 35 | RETVAL=$? 36 | echo "$PHP_CGI_NAME." 37 | } 38 | 39 | case "$1" in 40 | start) 41 | start 42 | ;; 43 | stop) 44 | stop 45 | ;; 46 | restart) 47 | stop 48 | start 49 | ;; 50 | *) 51 | echo "Usage: php-fastcgi {start|stop|restart}" 52 | exit 1 53 | ;; 54 | esac 55 | exit $RETVAL 56 | 57 | -------------------------------------------------------------------------------- /my_enginx_config/etc/nginx/fastcgi_params: -------------------------------------------------------------------------------- 1 | 2 | fastcgi_param QUERY_STRING $query_string; 3 | fastcgi_param REQUEST_METHOD $request_method; 4 | fastcgi_param CONTENT_TYPE $content_type; 5 | fastcgi_param CONTENT_LENGTH $content_length; 6 | 7 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 8 | fastcgi_param REQUEST_URI $request_uri; 9 | fastcgi_param DOCUMENT_URI $document_uri; 10 | fastcgi_param DOCUMENT_ROOT $document_root; 11 | fastcgi_param SERVER_PROTOCOL $server_protocol; 12 | 13 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 14 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 15 | 16 | fastcgi_param REMOTE_ADDR $remote_addr; 17 | fastcgi_param REMOTE_PORT $remote_port; 18 | fastcgi_param SERVER_ADDR $server_addr; 19 | fastcgi_param SERVER_PORT $server_port; 20 | fastcgi_param SERVER_NAME $server_name; 21 | 22 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 23 | fastcgi_param REDIRECT_STATUS 200; 24 | -------------------------------------------------------------------------------- /my_enginx_config/etc/nginx/more_complex_example.txt: -------------------------------------------------------------------------------- 1 | # user and group to run as 2 | user ez ez; 3 | 4 | # number of nginx workers 5 | worker_processes 6; 6 | 7 | # pid of nginx master process 8 | pid /var/run/nginx.pid; 9 | 10 | # Number of worker connections. 1024 is a good default 11 | events { 12 | worker_connections 1024; 13 | } 14 | 15 | # start the http module where we config http access. 16 | http { 17 | # pull in mime-types. You can break out your config 18 | # into as many include's as you want to make it cleaner 19 | include /etc/nginx/mime.types; 20 | 21 | # set a default type for the rare situation that 22 | # nothing matches from the mimie-type include 23 | default_type application/octet-stream; 24 | 25 | # configure log format 26 | log_format main '$remote_addr - $remote_user [$time_local] ' 27 | '"$request" $status $body_bytes_sent "$http_referer" ' 28 | '"$http_user_agent" "$http_x_forwarded_for"'; 29 | 30 | # main access log 31 | access_log /var/log/nginx_access.log main; 32 | 33 | # main error log 34 | error_log /var/log/nginx_error.log debug; 35 | 36 | # no sendfile on OSX 37 | sendfile on; 38 | 39 | # These are good default values. 40 | tcp_nopush on; 41 | tcp_nodelay off; 42 | # output compression saves bandwidth 43 | gzip on; 44 | gzip_http_version 1.0; 45 | gzip_comp_level 2; 46 | gzip_proxied any; 47 | gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml 48 | application/xml+rss text/javascript; 49 | 50 | 51 | # this is where you define your mongrel clusters. 52 | # you need one of these blocks for each cluster 53 | # and each one needs its own name to refer to it later. 54 | upstream mongrel { 55 | server 127.0.0.1:5000; 56 | server 127.0.0.1:5001; 57 | server 127.0.0.1:5002; 58 | } 59 | 60 | 61 | # the server directive is nginx's virtual host directive. 62 | server { 63 | # port to listen on. Can also be set to an IP:PORT 64 | listen 80; 65 | 66 | # Set the max size for file uploads to 50Mb 67 | client_max_body_size 50M; 68 | 69 | # sets the domain[s] that this vhost server requests for 70 | # server_name www.[engineyard].com [engineyard].com; 71 | 72 | # doc root 73 | root /data/ez/current/public; 74 | 75 | # vhost specific access log 76 | access_log /var/log/nginx.vhost.access.log main; 77 | 78 | # this rewrites all the requests to the maintenance.html 79 | # page if it exists in the doc root. This is for capistrano's 80 | # disable web task 81 | 82 | #######generaly i don not suggest to check file exists. disk is slow!! 83 | if (-f $document_root/system/maintenance.html) { 84 | rewrite ^(.*)$ /system/maintenance.html last; 85 | break; 86 | } 87 | 88 | location / { 89 | # needed to forward user's IP address to rails 90 | proxy_set_header X-Real-IP $remote_addr; 91 | 92 | # needed for HTTPS 93 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 94 | proxy_set_header Host $http_host; 95 | proxy_redirect false; 96 | proxy_max_temp_file_size 0; 97 | 98 | # If the file exists as a static file serve it directly without 99 | # running all the other rewite tests on it 100 | if (-f $request_filename) { #######generaly i don not suggest to check file exists. disk is slow!! 101 | break; 102 | } 103 | 104 | # check for index.html for directory index 105 | # if its there on the filesystem then rewite 106 | # the url to add /index.html to the end of it 107 | # and then break to send it to the next config rules. 108 | if (-f $request_filename/index.html) { 109 | rewrite (.*) $1/index.html break; 110 | } 111 | 112 | # this is the meat of the rails page caching config 113 | # it adds .html to the end of the url and then checks 114 | # the filesystem for that file. If it exists, then we 115 | # rewite the url to have explicit .html on the end 116 | # and then send it on its way to the next config rule. 117 | # if there is no file on the fs then it sets all the 118 | # necessary headers and proxies to our upstream mongrels 119 | if (-f $request_filename.html) { #######generaly i don not suggest to check file exists. disk is slow!! 120 | rewrite (.*) $1.html break; 121 | } 122 | 123 | if (!-f $request_filename) { #######generaly i don not suggest to check file exists. disk is slow!! 124 | proxy_pass http://mongrel; 125 | break; 126 | } 127 | } 128 | 129 | error_page 500 502 503 504 /500.html; 130 | location = /500.html { 131 | root /data/ez/current/public; 132 | } 133 | } 134 | 135 | # This server is setup for ssl. Uncomment if 136 | # you are using ssl as well as port 80. 137 | server { 138 | # port to listen on. Can also be set to an IP:PORT 139 | listen 443; 140 | 141 | # Set the max size for file uploads to 50Mb 142 | client_max_body_size 50M; 143 | 144 | # sets the domain[s] that this vhost server requests for 145 | # server_name www.[engineyard].com [engineyard].com; 146 | 147 | # doc root 148 | root /data/ez/current/public; 149 | 150 | # vhost specific access log 151 | access_log /var/log/nginx.vhost.access.log main; 152 | 153 | # this rewrites all the requests to the maintenance.html 154 | # page if it exists in the doc root. This is for capistrano's 155 | # disable web task 156 | if (-f $document_root/system/maintenance.html) { 157 | rewrite ^(.*)$ /system/maintenance.html last; 158 | break; 159 | } 160 | 161 | location / { 162 | # needed to forward user's IP address to rails 163 | proxy_set_header X-Real-IP $remote_addr; 164 | 165 | # needed for HTTPS 166 | proxy_set_header X_FORWARDED_PROTO https; 167 | 168 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 169 | proxy_set_header Host $http_host; 170 | proxy_redirect false; 171 | proxy_max_temp_file_size 0; 172 | 173 | # If the file exists as a static file serve it directly without 174 | # running all the other rewite tests on it 175 | if (-f $request_filename) { #######generaly i don not suggest to check file exists. disk is slow!! 176 | break; 177 | } 178 | 179 | # check for index.html for directory index 180 | # if its there on the filesystem then rewite 181 | # the url to add /index.html to the end of it 182 | # and then break to send it to the next config rules. 183 | if (-f $request_filename/index.html) { #######generaly i don not suggest to check file exists. disk is slow!! 184 | rewrite (.*) $1/index.html break; 185 | } 186 | 187 | # this is the meat of the rails page caching config 188 | # it adds .html to the end of the url and then checks 189 | # the filesystem for that file. If it exists, then we 190 | # rewite the url to have explicit .html on the end 191 | # and then send it on its way to the next config rule. 192 | # if there is no file on the fs then it sets all the 193 | # necessary headers and proxies to our upstream mongrels 194 | if (-f $request_filename.html) { #######generaly i don not suggest to check file exists. disk is slow!! 195 | rewrite (.*) $1.html break; 196 | } 197 | 198 | if (!-f $request_filename) { #######generaly i don not suggest to check file exists. disk is slow!! 199 | proxy_pass http://mongrel; 200 | break; 201 | } 202 | } 203 | 204 | error_page 500 502 503 504 /500.html; 205 | location = /500.html { 206 | root /data/ez/current/public; 207 | } 208 | } 209 | 210 | 211 | } 212 | -------------------------------------------------------------------------------- /my_enginx_config/etc/nginx/sites-enabled/default: -------------------------------------------------------------------------------- 1 | # You may add here your 2 | # server { 3 | # ... 4 | # } 5 | # statements for each of your virtual hosts 6 | keepalive_requests 1000; 7 | 8 | server { 9 | listen 80 default; 10 | server_name localhost; 11 | 12 | access_log /var/log/nginx/localhost.access.log; 13 | #access_log off; 14 | 15 | 16 | # location ~ ^/$ { 17 | # root /var/www/nginx-default; 18 | # #root /var/www/; 19 | # index index.html index.php; 20 | # } 21 | 22 | # location /doc { 23 | # root /usr/share; 24 | # autoindex on; 25 | # allow 127.0.0.1; 26 | # deny all; 27 | # } 28 | 29 | # location /images { 30 | # root /usr/share; 31 | # autoindex on; 32 | # } 33 | 34 | #error_page 404 /404.html; 35 | 36 | # redirect server error pages to the static page /50x.html 37 | # 38 | #error_page 500 502 503 504 /50x.html; 39 | #location = /50x.html { 40 | # root /var/www/nginx-default; 41 | #} 42 | 43 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 44 | # 45 | #location ~ \.php$ { 46 | #proxy_pass http://127.0.0.1; 47 | #} 48 | 49 | # setup below some locations for your website 50 | 51 | #some paths need to be piped directry like paths with rewrite, 52 | # and paths you want node to serve when nginx is the default server for it. 53 | location ~ ^/lib/ 54 | { 55 | # auth_basic "Hello, please login"; 56 | # auth_basic_user_file /var/www/htpasswd; 57 | 58 | proxy_pass http://127.0.0.1:8000; # uncomment this for this port will work for the root / of the website 59 | break; 60 | } 61 | 62 | location ~ ^/css/ 63 | { 64 | # auth_basic "Hello, please login"; 65 | # auth_basic_user_file /var/www/htpasswd; 66 | 67 | proxy_pass http://127.0.0.1:8000; 68 | break; 69 | } 70 | 71 | location ~ ^/js/ # i server the css and js and images cached from memory from node js so mine is probably faster then nginx's 72 | { 73 | # auth_basic "Hello, please login"; 74 | # auth_basic_user_file /var/www/htpasswd; 75 | 76 | proxy_pass http://127.0.0.1:8000; 77 | break; 78 | } 79 | 80 | location ~ ^/img/ 81 | { 82 | # auth_basic "Hello, please login"; 83 | # auth_basic_user_file /var/www/htpasswd; 84 | 85 | proxy_pass http://127.0.0.1:8000; 86 | break; 87 | } 88 | 89 | 90 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 91 | # 92 | 93 | location ~ \.php$ { 94 | #if ($uri !~ "^/uploads/") { 95 | fastcgi_pass 127.0.0.1:9000; 96 | fastcgi_index index.php; 97 | fastcgi_param SCRIPT_FILENAME /var/www/nginx-default$fastcgi_script_name; 98 | include fastcgi_params; 99 | #} 100 | break; 101 | } 102 | 103 | # to reload nginx settings type: 104 | # nginx -s reload 105 | 106 | # i prefer this instead fle not exist rout because this should work faster. 107 | #location ~ \.(js|css|jpg|png|gif|html)$ { 108 | # root /var/www/nginx-default; 109 | # break; 110 | #} 111 | 112 | 113 | # this app called data, you might want several apps. 114 | #location /data { 115 | # proxy_pass http://127.0.0.1:8000; 116 | #} 117 | 118 | #location ~ ^/$ { 119 | # root /var/www/nginx-default; 120 | # index index.html index.php; 121 | #} 122 | #location ~ ^/. { 123 | # root /var/www/nginx-default; 124 | # index index.html index.php; 125 | # if (!-f $request_filename) { 126 | # proxy_pass http://127.0.0.1:8000; # uncomment this for this port will work for the root / of the website 127 | # } 128 | #} 129 | 130 | #location / { 131 | # root /var/www/nginx-default; 132 | # index index.html index.php; 133 | # if (!-f $request_filename) { 134 | # proxy_pass http://127.0.0.1:8000; # uncomment this for this port will work for the root / of the website 135 | # } 136 | #} 137 | 138 | location ~ \.(js|css|jpg|png|gif|html)$ { 139 | root /var/www/nginx-default; 140 | break; 141 | } 142 | 143 | location / { 144 | root /var/www/nginx-default; 145 | index index.html index.php; 146 | proxy_pass http://127.0.0.1:8000; # uncomment this for this port will work for the root / of the website 147 | } 148 | 149 | 150 | # deny access to .htaccess files, if Apache's document root 151 | # concurs with nginx's one 152 | # 153 | #location ~ /\.ht { 154 | #deny all; 155 | #} 156 | } 157 | 158 | 159 | # another virtual host using mix of IP-, name-, and port-based configuration 160 | # 161 | #server { 162 | #listen 8000; 163 | #listen somename:8080; 164 | #server_name somename alias another.alias; 165 | 166 | #location / { 167 | #root html; 168 | #index index.html index.htm; 169 | #} 170 | #} 171 | 172 | 173 | # HTTPS server 174 | # 175 | #server { 176 | #listen 443; 177 | #server_name localhost; 178 | 179 | #ssl on; 180 | #ssl_certificate cert.pem; 181 | #ssl_certificate_key cert.key; 182 | 183 | #ssl_session_timeout 5m; 184 | 185 | #ssl_protocols SSLv2 SSLv3 TLSv1; 186 | #ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; 187 | #ssl_prefer_server_ciphers on; 188 | 189 | #location / { 190 | #root html; 191 | #index index.html index.htm; 192 | #} 193 | #} 194 | -------------------------------------------------------------------------------- /my_enginx_config/var/www/nginx-default/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | The page is temporarily unavailable 4 | 7 | 8 | 9 | 10 | 11 | 15 | 16 |
12 | The page you are looking for is temporarily unavailable.
13 | Please try again later. 14 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /my_enginx_config/var/www/nginx-default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Welcome to nginx! 4 | 5 | 6 |

Welcome to nginx!

7 | 8 | 9 | -------------------------------------------------------------------------------- /my_enginx_config/var/www/nginx-default/log.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Log 5 | 84 | 85 | 86 | 87 |

88 | 
89 | 
90 | 
91 | 


--------------------------------------------------------------------------------
/my_enginx_config/var/www/nginx-default/log.php:
--------------------------------------------------------------------------------
1 | 


--------------------------------------------------------------------------------
/my_enginx_config/var/www/nginx-default/moadmin.php:
--------------------------------------------------------------------------------
   1 |  password
  15 |  * You can add as many users as needed, eg.: array('scott' => 'tiger', 'samantha' => 'goldfish', 'gene' => 'alpaca')
  16 |  */
  17 | //$accessControl = array('scott' => 'tiger');
  18 | 
  19 | /**
  20 |  * To connect to a remote or authenticated Mongo instance, define the connection string in the MONGO_CONNECTION constant
  21 |  * mongodb://[username:password@]host1[:port1][,host2[:port2:],...]
  22 |  * If you do not know what this means then it is not relevant to your application and you can safely leave it as-is
  23 |  */
  24 | define('MONGO_CONNECTION', '');
  25 | 
  26 | /**
  27 |  * Sets the design theme - themes options are: swanky-purse, trontastic and classic
  28 |  */
  29 | define('THEME', 'swanky-purse');
  30 | 
  31 | /**
  32 |  * Default limit for number of objects to display per page - set to 0 for no limit
  33 |  */
  34 | define('OBJECT_LIMIT', 100);
  35 | 
  36 | /**
  37 |  * Vork core-functionality tools
  38 |  */
  39 | class get {
  40 |     /**
  41 |      * Opens up public access to config constants and variables and the cache object
  42 |      * @var object
  43 |      */
  44 |     public static $config;
  45 | 
  46 |     /**
  47 |      * Index of objects loaded, used to maintain uniqueness of singletons
  48 |      * @var array
  49 |      */
  50 |     public static $loadedObjects = array();
  51 | 
  52 |     /**
  53 |      * Overloads the php function htmlentities and changes the default charset to UTF-8 and the default value for the
  54 |      * fourth parameter $doubleEncode to false. Also adds ability to pass a null value to get the default $quoteStyle
  55 |      * and $charset (removes need to repeatedly define ENT_COMPAT, 'UTF-8', just to access the $doubleEncode argument)
  56 |      *
  57 |      * If you are using a PHP version prior to 5.2.3 the $doubleEncode parameter is not available so you will need
  58 |      * to comment out the last parameter in the return clause (including the preceding comma)
  59 |      *
  60 |      * @param string $string
  61 |      * @param int $quoteStyle Uses ENT_COMPAT if null or omitted
  62 |      * @param string $charset Uses UTF-8 if null or omitted
  63 |      * @param boolean $doubleEncode
  64 |      * @return string
  65 |      */
  66 |     public static function htmlentities($string, $quoteStyle = ENT_COMPAT, $charset = 'UTF-8', $doubleEncode = false) {
  67 |         return htmlentities($string, (!is_null($quoteStyle) ? $quoteStyle : ENT_COMPAT),
  68 |                             (!is_null($charset) ? $charset : 'UTF-8'), $doubleEncode);
  69 |     }
  70 | 
  71 |     /**
  72 |      * Initialize the character maps needed for the xhtmlentities() method and verifies the argument values
  73 |      * passed to it are valid.
  74 |      *
  75 |      * @param int $quoteStyle
  76 |      * @param string $charset Only valid options are UTF-8 and ISO-8859-1 (Latin-1)
  77 |      * @param boolean $doubleEncode
  78 |      */
  79 |     protected static function initXhtmlentities($quoteStyle, $charset, $doubleEncode) {
  80 |         $chars = get_html_translation_table(HTML_ENTITIES, $quoteStyle);
  81 |         if (isset($chars)) {
  82 |             unset($chars['<'], $chars['>']);
  83 |             $charMaps[$quoteStyle]['ISO-8859-1'][true] = $chars;
  84 |             $charMaps[$quoteStyle]['ISO-8859-1'][false] = array_combine(array_values($chars), $chars);
  85 |             $charMaps[$quoteStyle]['UTF-8'][true] = array_combine(array_map('utf8_encode', array_keys($chars)), $chars);
  86 |             $charMaps[$quoteStyle]['UTF-8'][false] = array_merge($charMaps[$quoteStyle]['ISO-8859-1'][false],
  87 |                                                                  $charMaps[$quoteStyle]['UTF-8'][true]);
  88 |             self::$loadedObjects['xhtmlEntities'] = $charMaps;
  89 |         }
  90 |         if (!isset($charMaps[$quoteStyle][$charset][$doubleEncode])) {
  91 |             if (!isset($chars)) {
  92 |                 $invalidArgument = 'quoteStyle = ' . $quoteStyle;
  93 |             } else if (!isset($charMaps[$quoteStyle][$charset])) {
  94 |                 $invalidArgument = 'charset = ' . $charset;
  95 |             } else {
  96 |                 $invalidArgument = 'doubleEncode = ' . (string) $doubleEncode;
  97 |             }
  98 |             trigger_error('Undefined argument sent to xhtmlentities() method: ' . $invalidArgument, E_USER_NOTICE);
  99 |         }
 100 |     }
 101 | 
 102 |     /**
 103 |      * Converts special characters in a string to XHTML-valid ASCII encoding the same as htmlentities except
 104 |      * this method allows the use of HTML tags within your string. Signature is the same as htmlentities except
 105 |      * that the only character sets available (third argument) are UTF-8 (default) and ISO-8859-1 (Latin-1).
 106 |      *
 107 |      * @param string $string
 108 |      * @param int $quoteStyle Constants available are ENT_NOQUOTES (default), ENT_QUOTES, ENT_COMPAT
 109 |      * @param string $charset Only valid options are UTF-8 (default) and ISO-8859-1 (Latin-1)
 110 |      * @param boolean $doubleEncode Default is false
 111 |      * @return string
 112 |      */
 113 |     public static function xhtmlentities($string, $quoteStyle = ENT_NOQUOTES, $charset = 'UTF-8',
 114 |                                          $doubleEncode = false) {
 115 |         $quoteStyles = array(ENT_NOQUOTES, ENT_QUOTES, ENT_COMPAT);
 116 |         $quoteStyle = (!in_array($quoteStyle, $quoteStyles) ? current($quoteStyles) : $quoteStyle);
 117 |         $charset = ($charset != 'ISO-8859-1' ? 'UTF-8' : $charset);
 118 |         $doubleEncode = (Boolean) $doubleEncode;
 119 |         if (!isset(self::$loadedObjects['xhtmlEntities'][$quoteStyle][$charset][$doubleEncode])) {
 120 |             self::initXhtmlentities($quoteStyle, $charset, $doubleEncode);
 121 |         }
 122 |         return strtr($string, self::$loadedObjects['xhtmlEntities'][$quoteStyle][$charset][$doubleEncode]);
 123 |     }
 124 | 
 125 |     /**
 126 |      * Loads an object as a singleton
 127 |      *
 128 |      * @param string $objectType
 129 |      * @param string $objectName
 130 |      * @return object
 131 |      */
 132 |     protected static function _loadObject($objectType, $objectName) {
 133 |         if (isset(self::$loadedObjects[$objectType][$objectName])) {
 134 |             return self::$loadedObjects[$objectType][$objectName];
 135 |         }
 136 |         $objectClassName = $objectName . ucfirst($objectType);
 137 |         if (class_exists($objectClassName)) {
 138 |             $objectObject = new $objectClassName;
 139 |             self::$loadedObjects[$objectType][$objectName] = $objectObject;
 140 |             return $objectObject;
 141 |         } else {
 142 |             $errorMsg = 'Class for ' . $objectType . ' ' . $objectName . ' could not be found';
 143 |         }
 144 |         trigger_error($errorMsg, E_USER_WARNING);
 145 |     }
 146 | 
 147 |     /**
 148 |      * Returns a helper object
 149 |      *
 150 |      * @param string $model
 151 |      * @return object
 152 |      */
 153 |     public static function helper($helper) {
 154 |         if (is_array($helper)) {
 155 |             array_walk($helper, array('self', __METHOD__));
 156 |             return;
 157 |         }
 158 |         if (!isset(self::$config['helpers']) || !in_array($helper, self::$config['helpers'])) {
 159 |             self::$config['helpers'][] = $helper;
 160 |         }
 161 |         return self::_loadObject('helper', $helper);
 162 |     }
 163 | }
 164 | 
 165 | /**
 166 |  * Thrown when the mongod server is not accessible
 167 |  */
 168 | class cannotConnectToMongoServer extends Exception {
 169 |     public function __toString() {
 170 |         return '

Cannot connect to the MongoDB database.

' . PHP_EOL . 'If Mongo is installed then be sure that' 171 | . ' an instance of the "mongod" server, not "mongo" shell, is running.
' . PHP_EOL 172 | . 'Instructions and database download: http://vork.us/go/fhk4'; 173 | } 174 | } 175 | 176 | /** 177 | * Thrown when the mongo extension for PHP is not installed 178 | */ 179 | class mongoExtensionNotInstalled extends Exception { 180 | public function __toString() { 181 | return '

PHP cannot access MongoDB, you need to install the Mongo extension for PHP.

' 182 | . PHP_EOL . 'Instructions and driver download: ' 183 | . 'http://vork.us/go/tv27'; 184 | } 185 | } 186 | 187 | /** 188 | * phpMoAdmin data model 189 | */ 190 | class moadminModel { 191 | /** 192 | * mongo connection - if a MongoDB object already exists (from a previous script) then only DB operations use this 193 | * @var Mongo 194 | */ 195 | protected $_db; 196 | 197 | /** 198 | * MongoDB 199 | * @var MongoDB 200 | */ 201 | public $mongo; 202 | 203 | /** 204 | * Returns a new Mongo connection 205 | * @return Mongo 206 | */ 207 | protected function _mongo() { 208 | return (!MONGO_CONNECTION ? new Mongo() : new Mongo(MONGO_CONNECTION)); 209 | } 210 | 211 | /** 212 | * Connects to a Mongo database if the name of one is supplied as an argument 213 | * @param string $db 214 | */ 215 | public function __construct($db = null) { 216 | if ($db) { 217 | if (!extension_loaded('mongo')) { 218 | throw new mongoExtensionNotInstalled(); 219 | } 220 | try { 221 | $this->_db = $this->_mongo(); 222 | $this->mongo = $this->_db->selectDB($db); 223 | } catch (MongoConnectionException $e) { 224 | throw new cannotConnectToMongoServer(); 225 | } 226 | } 227 | } 228 | 229 | /** 230 | * Executes a native JS MongoDB command 231 | * This method is not currently used for anything 232 | * @param string $cmd 233 | * @return mixed 234 | */ 235 | protected function _exec($cmd) { 236 | $exec = $this->mongo->execute($cmd); 237 | return $exec['retval']; 238 | } 239 | 240 | /** 241 | * Change the DB connection 242 | * @param string $db 243 | */ 244 | public function setDb($db) { 245 | if (!isset($this->_db)) { 246 | $this->_db = $this->_mongo(); 247 | } 248 | $this->mongo = $this->_db->selectDB($db); 249 | } 250 | 251 | /** 252 | * Total size of all the databases 253 | * @var int 254 | */ 255 | public $totalDbSize = 0; 256 | 257 | /** 258 | * Gets list of databases 259 | * @return array 260 | */ 261 | public function listDbs() { 262 | $dbs = $this->_db->selectDB('admin')->command(array('listDatabases' => 1)); 263 | $this->totalDbSize = $dbs['totalSize']; 264 | foreach ($dbs['databases'] as $db) { 265 | $return[$db['name']] = $db['name'] . ' (' 266 | . (!$db['empty'] ? round($db['sizeOnDisk'] / 1000000) . 'mb' : 'empty') . ')'; 267 | } 268 | ksort($return); 269 | $dbCount = 0; 270 | foreach ($return as $key => $val) { 271 | $return[$key] = ++$dbCount . '. ' . $val; 272 | } 273 | return $return; 274 | } 275 | 276 | /** 277 | * Generate system info and stats 278 | * @return array 279 | */ 280 | public function getStats() { 281 | $admin = $this->_db->selectDB('admin'); 282 | $return = array_merge($admin->command(array('buildinfo' => 1)), 283 | $admin->command(array('serverStatus' => 1))); 284 | $profile = $admin->command(array('profile' => -1)); 285 | $return['profilingLevel'] = $profile['was']; 286 | $return['mongoDbTotalSize'] = round($this->totalDbSize / 1000000) . 'mb'; 287 | $prevError = $admin->command(array('getpreverror' => 1)); 288 | if (!$prevError['n']) { 289 | $return['previousDbErrors'] = 'None'; 290 | } else { 291 | $return['previousDbErrors']['error'] = $prevError['err']; 292 | $return['previousDbErrors']['numberOfOperationsAgo'] = $prevError['nPrev']; 293 | } 294 | $return['globalLock']['totalTime'] .= ' µSec'; 295 | $return['uptime'] = round($return['uptime'] / 60) . ':' . str_pad($return['uptime'] % 60, 2, '0', STR_PAD_LEFT) 296 | . ' minutes'; 297 | $unshift['mongo'] = $return['version']; 298 | $unshift['mongoPhpDriver'] = Mongo::VERSION; 299 | $unshift['phpMoAdmin'] = '1.0.6'; 300 | $unshift['gitVersion'] = $return['gitVersion']; 301 | unset($return['ok'], $return['version'], $return['gitVersion']); 302 | $return = array_merge(array('version' => $unshift), $return); 303 | $iniIndex = array(-1 => 'Unlimited', 'Off', 'On'); 304 | $phpIni = array('allow_persistent', 'auto_reconnect', 'chunk_size', 'cmd', 'default_host', 'default_port', 305 | 'max_connections', 'max_persistent'); 306 | foreach ($phpIni as $ini) { 307 | $key = 'php_' . $ini; 308 | $return[$key] = ini_get('mongo.' . $ini); 309 | if (isset($iniIndex[$return[$key]])) { 310 | $return[$key] = $iniIndex[$return[$key]]; 311 | } 312 | } 313 | return $return; 314 | } 315 | 316 | /** 317 | * Repairs a database 318 | * @return array Success status 319 | */ 320 | public function repairDb() { 321 | return $this->mongo->repair(); 322 | } 323 | 324 | /** 325 | * Drops a database 326 | */ 327 | public function dropDb() { 328 | $this->mongo->drop(); 329 | return; 330 | if (!isset($this->_db)) { 331 | $this->_db = $this->_mongo(); 332 | } 333 | $this->_db->dropDB($this->mongo); 334 | } 335 | 336 | /** 337 | * Gets a list of database collections 338 | * @return array 339 | */ 340 | public function listCollections() { 341 | $collections = array(); 342 | $MongoCollectionObjects = $this->mongo->listCollections(); 343 | foreach ($MongoCollectionObjects as $collection) { 344 | $collection = substr(strstr((string) $collection, '.'), 1); 345 | $collections[$collection] = $this->mongo->selectCollection($collection)->count(); 346 | } 347 | ksort($collections); 348 | return $collections; 349 | } 350 | 351 | /** 352 | * Drops a collection 353 | * @param string $collection 354 | */ 355 | public function dropCollection($collection) { 356 | $this->mongo->selectCollection($collection)->drop(); 357 | } 358 | 359 | /** 360 | * Creates a collection 361 | * @param string $collection 362 | */ 363 | public function createCollection($collection) { 364 | if ($collection) { 365 | $this->mongo->createCollection($collection); 366 | } 367 | } 368 | 369 | /** 370 | * Gets a list of the indexes on a collection 371 | * 372 | * @param string $collection 373 | * @return array 374 | */ 375 | public function listIndexes($collection) { 376 | return $this->mongo->selectCollection($collection)->getIndexInfo(); 377 | } 378 | 379 | /** 380 | * Ensures an index 381 | * 382 | * @param string $collection 383 | * @param array $indexes 384 | * @param array $unique 385 | */ 386 | public function ensureIndex($collection, array $indexes, array $unique) { 387 | $unique = ($unique ? true : false); //signature requires a bool in both Mongo v. 1.0.1 and 1.2.0 388 | $this->mongo->selectCollection($collection)->ensureIndex($indexes, $unique); 389 | } 390 | 391 | /** 392 | * Removes an index 393 | * 394 | * @param string $collection 395 | * @param array $index Must match the array signature of the index 396 | */ 397 | public function deleteIndex($collection, array $index) { 398 | $this->mongo->selectCollection($collection)->deleteIndex($index); 399 | } 400 | 401 | /** 402 | * Sort array - currently only used for collections 403 | * @var array 404 | */ 405 | public $sort = array('_id' => 1); 406 | 407 | /** 408 | * Number of rows in the entire resultset (before limit-clause is applied) 409 | * @var int 410 | */ 411 | public $count; 412 | 413 | /** 414 | * Array keys in the first and last object in a collection merged together (used to build sort-by options) 415 | * @var array 416 | */ 417 | public $colKeys = array(); 418 | 419 | /** 420 | * Get the records in a collection 421 | * 422 | * @param string $collection 423 | * @return array 424 | */ 425 | public function listRows($collection) { 426 | foreach ($this->sort as $key => $val) { //cast vals to int 427 | $sort[$key] = (int) $val; 428 | } 429 | $col = $this->mongo->selectCollection($collection); 430 | $this->count = $col->count(); 431 | $cur = $col->find()->sort($sort); 432 | if ($_SESSION['limit'] && $this->count > $_SESSION['limit']) { 433 | if ($this->count > 1) { 434 | $this->colKeys = phpMoAdmin::getArrayKeys($col->findOne()); 435 | } 436 | $cur->limit($_SESSION['limit']); 437 | if (isset($_GET['skip'])) { 438 | if ($this->count <= $_GET['skip']) { 439 | $_GET['skip'] = ($this->count - $_SESSION['limit']); 440 | } 441 | $cur->skip($_GET['skip']); 442 | } 443 | } else if ($this->count > 1) { 444 | $this->colKeys = phpMoAdmin::getArrayKeys($cur->getNext()); 445 | } 446 | if ($this->count > 1) { 447 | $curLast = $col->find()->sort($sort); 448 | if ($this->count > 2) { 449 | $curLast->skip(min($this->count, 100) - 1); 450 | } 451 | $this->colKeys = array_merge($this->colKeys, phpMoAdmin::getArrayKeys($curLast->getNext())); 452 | ksort($this->colKeys); 453 | } 454 | return $cur; 455 | } 456 | 457 | /** 458 | * Returns a serialized element back to its native PHP form 459 | * 460 | * @param string $_id 461 | * @param string $idtype 462 | * @return mixed 463 | */ 464 | protected function _unserialize($_id, $idtype) { 465 | if ($idtype == 'object') { 466 | $errLevel = error_reporting(); 467 | error_reporting(0); //unserializing an object that is not serialized throws a warning 468 | $_idObj = unserialize($_id); 469 | error_reporting($errLevel); 470 | if ($_idObj !== false) { 471 | $_id = $_idObj; 472 | } 473 | } else if (gettype($_id) != $idtype) { 474 | settype($_id, $idtype); 475 | } 476 | return $_id; 477 | } 478 | 479 | /** 480 | * Removes an object from a collection 481 | * 482 | * @param string $collection 483 | * @param string $_id 484 | * @param string $idtype 485 | */ 486 | public function removeObject($collection, $_id, $idtype) { 487 | $this->mongo->selectCollection($collection)->remove(array('_id' => $this->_unserialize($_id, $idtype))); 488 | } 489 | 490 | /** 491 | * Retieves an object for editing 492 | * 493 | * @param string $collection 494 | * @param string $_id 495 | * @param string $idtype 496 | * @return array 497 | */ 498 | public function editObject($collection, $_id, $idtype) { 499 | return $this->mongo->selectCollection($collection)->findOne(array('_id' => $this->_unserialize($_id, $idtype))); 500 | } 501 | 502 | /** 503 | * Saves an object 504 | * 505 | * @param string $collection 506 | * @param string $obj 507 | * @return array 508 | */ 509 | public function saveObject($collection, $obj) { 510 | eval('$obj=' . $obj . ';'); //cast from string to array 511 | return $this->mongo->selectCollection($collection)->save($obj); 512 | } 513 | } 514 | 515 | /** 516 | * phpMoAdmin application control 517 | */ 518 | class moadminComponent { 519 | /** 520 | * $this->mongo is used to pass properties from component to view without relying on a controller to return them 521 | * @var array 522 | */ 523 | public $mongo = array(); 524 | 525 | /** 526 | * Model object 527 | * @var moadminModel 528 | */ 529 | public static $model; 530 | 531 | /** 532 | * Routes requests and sets return data 533 | */ 534 | public function __construct() { 535 | if (class_exists('mvc')) { 536 | mvc::$view = '#moadmin'; 537 | } 538 | $this->mongo['dbs'] = self::$model->listDbs(); 539 | if (isset($_GET['db'])) { 540 | if (strpos($_GET['db'], '.') !== false) { 541 | $_GET['db'] = $_GET['newdb']; 542 | } 543 | self::$model->setDb($_GET['db']); 544 | } 545 | 546 | if (isset($_POST['limit'])) { 547 | $_SESSION['limit'] = (int) $_POST['limit']; 548 | } else if (!isset($_SESSION['limit'])) { 549 | $_SESSION['limit'] = OBJECT_LIMIT; 550 | } 551 | 552 | $action = (isset($_GET['action']) ? $_GET['action'] : 'listCollections'); 553 | if (isset($_POST['object'])) { 554 | $obj = self::$model->saveObject($_GET['collection'], $_POST['object']); 555 | $_GET['_id'] = $obj['_id']; 556 | $action = 'listRows'; 557 | } else if ($action == 'createCollection') { 558 | self::$model->$action($_GET['collection']); 559 | } 560 | 561 | if (isset($_GET['sort']) && is_array($_GET['sort'])) { 562 | self::$model->sort = $_GET['sort']; 563 | } 564 | 565 | $this->mongo['listCollections'] = self::$model->listCollections(); 566 | if ($action == 'editObject') { 567 | $this->mongo[$action] = (isset($_GET['_id']) 568 | ? self::$model->$action($_GET['collection'], $_GET['_id'], $_GET['idtype']) : ''); 569 | return; 570 | } else if ($action == 'removeObject') { 571 | self::$model->$action($_GET['collection'], $_GET['_id'], $_GET['idtype']); 572 | $action = 'listRows'; 573 | } else if ($action == 'ensureIndex') { 574 | foreach ($_GET['index'] as $key => $field) { 575 | $indexes[$field] = (isset($_GET['isdescending'][$key]) && $_GET['isdescending'][$key] ? -1 : 1); 576 | } 577 | self::$model->$action($_GET['collection'], $indexes, ($_GET['unique'] == 'Unique' ? array('unique' => true) 578 | : array())); 579 | $action = 'listCollections'; 580 | } else if ($action == 'deleteIndex') { 581 | self::$model->$action($_GET['collection'], unserialize($_GET['index'])); 582 | $action = 'listRows'; 583 | } else if ($action == 'getStats') { 584 | $this->mongo[$action] = self::$model->$action(); 585 | unset($this->mongo['listCollections']); 586 | } else if ($action == 'repairDb' || $action == 'getStats') { 587 | $this->mongo[$action] = self::$model->$action(); 588 | $action = 'listCollections'; 589 | } else if ($action == 'dropDb') { 590 | self::$model->$action(); 591 | header('Location: ' . $_SERVER['SCRIPT_NAME']); 592 | return; 593 | } 594 | 595 | if (isset($_GET['collection']) && $action != 'listCollections' && method_exists(self::$model, $action)) { 596 | $this->mongo[$action] = self::$model->$action($_GET['collection']); 597 | $this->mongo['count'] = self::$model->count; 598 | $this->mongo['colKeys'] = self::$model->colKeys; 599 | } 600 | if ($action == 'listRows') { 601 | $this->mongo['listIndexes'] = self::$model->listIndexes($_GET['collection']); 602 | } else if ($action == 'dropCollection') { 603 | $this->mongo['listCollections'] = self::$model->listCollections(); 604 | } 605 | } 606 | } 607 | 608 | /** 609 | * HTML helper tools 610 | */ 611 | class htmlHelper { 612 | /** 613 | * Internal storage of the link-prefix and hypertext protocol values 614 | * @var string 615 | */ 616 | protected $_linkPrefix, $_protocol; 617 | 618 | /** 619 | * Internal list of included CSS & JS files used by $this->_tagBuilder() to assure that files are not included twice 620 | * @var array 621 | */ 622 | protected $_includedFiles = array(); 623 | 624 | /** 625 | * Flag array to avoid defining singleton JavaScript & CSS snippets more than once 626 | * @var array 627 | */ 628 | protected $_jsSingleton = array(), $_cssSingleton = array(); 629 | 630 | /** 631 | * Sets the protocol (http/https) 632 | */ 633 | public function __construct() { 634 | if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { 635 | $this->_linkPrefix = 'http://' . $_SERVER['HTTP_HOST']; 636 | $this->_protocol = 'https://'; 637 | } else { 638 | $this->_protocol = 'http://'; 639 | } 640 | } 641 | 642 | /** 643 | * Creates simple HTML wrappers, accessed via $this->__call() 644 | * 645 | * JS and CSS files are never included more than once even if requested twice. If DEBUG mode is enabled than the 646 | * second request will be added to the debug log as a duplicate. The jsSingleton and cssSingleton methods operate 647 | * the same as the js & css methods except that they will silently skip duplicate requests instead of logging them. 648 | * 649 | * jsInlineSingleton and cssInlineSingleton makes sure a JavaScript or CSS snippet will only be output once, even 650 | * if echoed out multiple times and this method will attempt to place the JS code into the head section, if 651 | * has already been echoed out then it will return the JS code inline the same as jsInline. Eg.: 652 | * $helloJs = "function helloWorld() {alert('Hello World');}"; 653 | * echo $html->jsInlineSingleton($helloJs); 654 | * 655 | * Adding an optional extra argument to jsInlineSingleton/cssInlineSingleton will return the inline code bare (plus 656 | * a trailing linebreak) if it cannot place it into the head section, this is used for joint JS/CSS statements: 657 | * echo $html->jsInline($html->jsInlineSingleton($helloJs, true) . 'helloWorld();'); 658 | * 659 | * @param string $tagType 660 | * @param array $args 661 | * @return string 662 | */ 663 | protected function _tagBuilder($tagType, $args = array()) { 664 | $arg = current($args); 665 | if (empty($arg) || $arg === '') { 666 | $errorMsg = 'Missing argument for ' . __CLASS__ . '::' . $tagType . '()'; 667 | trigger_error($errorMsg, E_USER_WARNING); 668 | } 669 | 670 | if (is_array($arg)) { 671 | foreach ($arg as $thisArg) { 672 | $return[] = $this->_tagBuilder($tagType, array($thisArg)); 673 | } 674 | $return = implode(PHP_EOL, $return); 675 | } else { 676 | switch ($tagType) { 677 | case 'js': 678 | case 'jsSingleton': 679 | case 'css': //Optional extra argument to define CSS media type 680 | case 'cssSingleton': 681 | case 'jqueryTheme': 682 | if ($tagType == 'jqueryTheme') { 683 | $arg = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/' 684 | . str_replace(' ', '-', strtolower($arg)) . '/jquery-ui.css'; 685 | $tagType = 'css'; 686 | } 687 | if (!isset($this->_includedFiles[$tagType][$arg])) { 688 | if ($tagType == 'css' || $tagType == 'cssSingleton') { 689 | $return = ''; 691 | } else { 692 | $return = ''; 693 | } 694 | $this->_includedFiles[$tagType][$arg] = true; 695 | } else { 696 | $return = null; 697 | if (DEBUG_MODE && ($tagType == 'js' || $tagType == 'css')) { 698 | debug::log($arg . $tagType . ' file has already been included', 'warn'); 699 | } 700 | } 701 | break; 702 | case 'cssInline': //Optional extra argument to define CSS media type 703 | $return = ''; 710 | break; 711 | case 'jsInline': 712 | $return = ''; 719 | break; 720 | case 'jsInlineSingleton': //Optional extra argument to supress adding of inline JS/CSS wrapper 721 | case 'cssInlineSingleton': 722 | $tagTypeBase = substr($tagType, 0, -15); 723 | $return = null; 724 | $md5 = md5($arg); 725 | if (!isset($this->{'_' . $tagTypeBase . 'Singleton'}[$md5])) { 726 | $this->{'_' . $tagTypeBase . 'Singleton'}[$md5] = true; 727 | if (!$this->_bodyOpen) { 728 | $this->vorkHead[$tagTypeBase . 'Inline'][] = $arg; 729 | } else { 730 | $return = (!isset($args[1]) || !$args[1] ? $this->{$tagTypeBase . 'Inline'}($arg) 731 | : $arg . PHP_EOL); 732 | } 733 | } 734 | break; 735 | case 'div': 736 | case 'li': 737 | case 'p': 738 | case 'h1': 739 | case 'h2': 740 | case 'h3': 741 | case 'h4': 742 | $return = '<' . $tagType . '>' . $arg . ''; 743 | break; 744 | default: 745 | $errorMsg = 'TagType ' . $tagType . ' not valid in ' . __CLASS__ . '::' . __METHOD__; 746 | throw new Exception($errorMsg); 747 | break; 748 | } 749 | } 750 | return $return; 751 | } 752 | 753 | /** 754 | * Creates virtual wrapper methods via $this->_tagBuilder() for the simple wrapper functions including: 755 | * $html->css, js, cssInline, jsInline, div, li, p and h1-h4 756 | * 757 | * @param string $method 758 | * @param array $arg 759 | * @return string 760 | */ 761 | public function __call($method, $args) { 762 | $validTags = array('css', 'js', 'cssSingleton', 'jsSingleton', 'jqueryTheme', 763 | 'cssInline', 'jsInline', 'jsInlineSingleton', 'cssInlineSingleton', 764 | 'div', 'li', 'p', 'h1', 'h2', 'h3', 'h4'); 765 | if (in_array($method, $validTags)) { 766 | return $this->_tagBuilder($method, $args); 767 | } else { 768 | $errorMsg = 'Call to undefined method ' . __CLASS__ . '::' . $method . '()'; 769 | trigger_error($errorMsg, E_USER_ERROR); 770 | } 771 | } 772 | 773 | /** 774 | * Flag to make sure that header() can only be opened one-at-a-time and footer() can only be used after header() 775 | * @var boolean 776 | */ 777 | private $_bodyOpen = false; 778 | 779 | /** 780 | * Sets the default doctype to XHTML 1.1 781 | * @var string 782 | */ 783 | protected $_docType = ''; 784 | 785 | /** 786 | * Allows modification of the docType 787 | * 788 | * Can either set to an actual doctype definition or to one of the presets (case-insensitive): 789 | * XHTML Mobile 1.2 790 | * XHTML Mobile 1.1 791 | * XHTML Mobile 1.0 792 | * Mobile 1.2 (alias for XHTML Mobile 1.2) 793 | * Mobile 1.1 (alias for XHTML Mobile 1.1) 794 | * Mobile 1.0 (alias for XHTML Mobile 1.0) 795 | * Mobile (alias for the most-strict Mobile DTD, currently 1.2) 796 | * XHTML 1.1 (this is the default DTD, there is no need to apply this method for an XHTML 1.1 doctype) 797 | * XHTML (Alias for XHTML 1.1) 798 | * XHTML 1.0 Strict 799 | * XHTML 1.0 Transitional 800 | * XHTML 1.0 Frameset 801 | * XHTML 1.0 (Alias for XHTML 1.0 Strict) 802 | * HTML 5 803 | * HTML 4.01 804 | * HTML (Alias for HTML 4.01) 805 | * 806 | * @param string $docType 807 | */ 808 | public function setDocType($docType) { 809 | $docType = str_replace(' ', '', strtolower($docType)); 810 | if ($docType == 'xhtml1.1' || $docType == 'xhtml') { 811 | return; //XHTML 1.1 is the default 812 | } else if ($docType == 'xhtml1.0') { 813 | $docType = 'strict'; 814 | } 815 | $docType = str_replace(array('xhtml mobile', 'xhtml1.0'), array('mobile', ''), $docType); 816 | $docTypes = array( 817 | 'mobile1.2' => '', 819 | 'mobile1.1' => '', 821 | 'mobile1.0' => '', 823 | 'strict' => '', 825 | 'transitional' => '', 827 | 'frameset' => '', 829 | 'html4.01' => '', 831 | 'html5' => '' 832 | ); 833 | $docTypes['mobile'] = $docTypes['mobile1.2']; 834 | $docTypes['html'] = $docTypes['html4.01']; 835 | $this->_docType = (isset($docTypes[$docType]) ? $docTypes[$docType] : $docType); 836 | } 837 | 838 | /** 839 | * Array used internally by Vork to cache JavaScript and CSS snippets and place them in the head section 840 | * Changing the contents of this property may cause Vork components to be rendered incorrectly. 841 | * @var array 842 | */ 843 | public $vorkHead = array(); 844 | 845 | /** 846 | * Returns an HTML header and opens the body container 847 | * This method will trigger an error if executed more than once without first calling 848 | * the footer() method on the prior usage 849 | * This is meant to be utilized within layouts, not views (but will work in either) 850 | * 851 | * @param array $args 852 | * @return string 853 | */ 854 | public function header(array $args) { 855 | if (!$this->_bodyOpen) { 856 | $this->_bodyOpen = true; 857 | extract($args); 858 | $return = $this->_docType 859 | . PHP_EOL . '' 860 | . PHP_EOL . '' 861 | . PHP_EOL . '' . $title . ''; 862 | 863 | if (!isset($metaheader['Content-Type'])) { 864 | $metaheader['Content-Type'] = 'text/html; charset=utf-8'; 865 | } 866 | foreach ($metaheader as $name => $content) { 867 | $return .= PHP_EOL . ''; 868 | } 869 | 870 | $meta['generator'] = 'Vork 2.00'; 871 | foreach ($meta as $name => $content) { 872 | $return .= PHP_EOL . ''; 873 | } 874 | 875 | if (isset($favicon)) { 876 | $return .= PHP_EOL . ''; 877 | } 878 | if (isset($animatedFavicon)) { 879 | $return .= PHP_EOL . ''; 880 | } 881 | 882 | $containers = array('css', 'cssInline', 'js', 'jsInline', 'jqueryTheme'); 883 | foreach ($containers as $container) { 884 | if (isset($$container)) { 885 | $return .= PHP_EOL . $this->$container($$container); 886 | } 887 | } 888 | 889 | if ($this->vorkHead) { //used internally by Vork tools 890 | foreach ($this->vorkHead as $container => $objArray) { //works only for inline code, not external files 891 | $return .= PHP_EOL . $this->$container(implode(PHP_EOL, $objArray)); 892 | } 893 | } 894 | 895 | if (isset($head)) { 896 | $return .= PHP_EOL . (is_array($head) ? implode(PHP_EOL, $head) : $head); 897 | } 898 | 899 | $return .= PHP_EOL . '' . PHP_EOL . ''; 900 | return $return; 901 | } else { 902 | $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - the header has already been returned'; 903 | trigger_error($errorMsg, E_USER_NOTICE); 904 | } 905 | } 906 | 907 | /** 908 | * Returns an HTML footer and optional Google Analytics 909 | * This method will trigger an error if executed without first calling the header() method 910 | * This is meant to be utilized within layouts, not views (but will work in either) 911 | * 912 | * @param array $args 913 | * @return string 914 | */ 915 | public function footer(array $args = array()) { 916 | if ($this->_bodyOpen) { 917 | $this->_bodyOpen = false; 918 | return ''; 919 | } else { 920 | $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - header() has not been called'; 921 | trigger_error($errorMsg, E_USER_NOTICE); 922 | } 923 | } 924 | 925 | /** 926 | * Establishes a basic set of JavaScript tools, just echo $html->jsTools() before any JavaScript code that 927 | * will use the tools. 928 | * 929 | * This method will only operate from the first occurrence in your code, subsequent calls will not output anything 930 | * but you should add it anyway as it will make sure that your code continues to work if you later remove a 931 | * previous call to jsTools. 932 | * 933 | * Tools provided: 934 | * 935 | * dom() method is a direct replacement for document.getElementById() that works in all JS-capable 936 | * browsers Y2k and newer. 937 | * 938 | * vork object - defines a global vork storage space; use by appending your own properties, eg.: vork.widgetCount 939 | * 940 | * @param Boolean $noJsWrapper set to True if calling from within a $html->jsInline() wrapper 941 | * @return string 942 | */ 943 | public function jsTools($noJsWrapper = false) { 944 | return $this->jsInlineSingleton("var vork = function() {} 945 | var dom = function(id) { 946 | if (typeof document.getElementById != 'undefined') { 947 | dom = function(id) {return document.getElementById(id);} 948 | } else if (typeof document.all != 'undefined') { 949 | dom = function(id) {return document.all[id];} 950 | } else { 951 | return false; 952 | } 953 | return dom(id); 954 | }", $noJsWrapper); 955 | } 956 | 957 | /** 958 | * Load a JavaScript library via Google's AJAX API 959 | * http://code.google.com/apis/ajaxlibs/documentation/ 960 | * 961 | * Version is optional and can be exact (1.8.2) or just version-major (1 or 1.8) 962 | * 963 | * Usage: 964 | * echo $html->jsLoad('jquery'); 965 | * echo $html->jsLoad(array('yui', 'mootools')); 966 | * echo $html->jsLoad(array('yui' => 2.7, 'jquery', 'dojo' => '1.3.1', 'scriptaculous')); 967 | * 968 | * //You can also use the Google API format JSON-decoded in which case version is required & name must be lowercase 969 | * $jsLibs = array(array('name' => 'mootools', 'version' => 1.2, 'base_domain' => 'ditu.google.cn'), array(...)); 970 | * echo $html->jsLoad($jsLibs); 971 | * 972 | * @param mixed $library Can be a string, array(str1, str2...) or , array(name1 => version1, name2 => version2...) 973 | * or JSON-decoded Google API syntax array(array('name' => 'yui', 'version' => 2), array(...)) 974 | * @param mixed $version Optional, int or str, this is only used if $library is a string 975 | * @param array $options Optional, passed to Google "optionalSettings" argument, only used if $library == str 976 | * @return str 977 | */ 978 | public function jsLoad($library, $version = null, array $options = array()) { 979 | $versionDefaults = array('swfobject' => 2, 'yui' => 2, 'ext-core' => 3, 'mootools' => 1.2); 980 | if (!is_array($library)) { //jsLoad('yui') 981 | $library = strtolower($library); 982 | if (!$version) { 983 | $version = (!isset($versionDefaults[$library]) ? 1 : $versionDefaults[$library]); 984 | } 985 | $library = array('name' => $library, 'version' => $version); 986 | $library = array(!$options ? $library : array_merge($library, $options)); 987 | } else { 988 | foreach ($library as $key => $val) { 989 | if (!is_array($val)) { 990 | if (is_int($key)) { //jsLoad(array('yui', 'prototype')) 991 | $val = strtolower($val); 992 | $version = (!isset($versionDefaults[$val]) ? 1 : $versionDefaults[$val]); 993 | $library[$key] = array('name' => $val, 'version' => $version); 994 | } else if (!is_array($val)) { // //jsLoad(array('yui' => '2.8.0r4', 'prototype' => 1.6)) 995 | $library[$key] = array('name' => strtolower($key), 'version' => $val); 996 | } 997 | } 998 | } 999 | } 1000 | $url = $this->_protocol . 'www.google.com/jsapi'; 1001 | if (!isset($this->_includedFiles['js'][$url])) { //autoload library 1002 | $this->_includedFiles['js'][$url] = true; 1003 | $url .= '?autoload=' . urlencode(json_encode(array('modules' => array_values($library)))); 1004 | $return = $this->js($url); 1005 | } else { //load inline 1006 | foreach ($library as $lib) { 1007 | $js = 'google.load("' . $lib['name'] . '", "' . $lib['version'] . '"'; 1008 | if (count($lib) > 2) { 1009 | unset($lib['name'], $lib['version']); 1010 | $js .= ', ' . json_encode($lib); 1011 | } 1012 | $jsLoads[] = $js . ');'; 1013 | } 1014 | $return = $this->jsInline(implode(PHP_EOL, $jsLoads)); 1015 | } 1016 | return $return; 1017 | } 1018 | 1019 | /** 1020 | * Takes an array of key-value pairs and formats them in the syntax of HTML-container properties 1021 | * 1022 | * @param array $properties 1023 | * @return string 1024 | */ 1025 | public static function formatProperties(array $properties) { 1026 | $return = array(); 1027 | foreach ($properties as $name => $value) { 1028 | $return[] = $name . '="' . get::htmlentities($value) . '"'; 1029 | } 1030 | return implode(' ', $return); 1031 | } 1032 | 1033 | /** 1034 | * Creates an anchor or link container 1035 | * 1036 | * @param array $args 1037 | * @return string 1038 | */ 1039 | public function anchor(array $args) { 1040 | if (!isset($args['text']) && isset($args['href'])) { 1041 | $args['text'] = $args['href']; 1042 | } 1043 | if (!isset($args['title']) && isset($args['text'])) { 1044 | $args['title'] = str_replace(array("\n", "\r"), ' ', strip_tags($args['text'])); 1045 | } 1046 | $return = ''; 1047 | if (isset($args['ajaxload'])) { 1048 | $return = $this->jsSingleton('/js/ajax.js'); 1049 | $onclick = "return ajax.load('" . $args['ajaxload'] . "', this.href);"; 1050 | $args['onclick'] = (!isset($args['onclick']) ? $onclick : $args['onclick'] . '; ' . $onclick); 1051 | unset($args['ajaxload']); 1052 | } 1053 | $text = (isset($args['text']) ? $args['text'] : null); 1054 | unset($args['text']); 1055 | return $return . '' . $text . ''; 1056 | } 1057 | 1058 | /** 1059 | * Shortcut to access the anchor method 1060 | * 1061 | * @param str $href 1062 | * @param str $text 1063 | * @param array $args 1064 | * @return str 1065 | */ 1066 | public function link($href, $text = null, array $args = array()) { 1067 | if (strpos($href, 'http') !== 0) { 1068 | $href = $this->_linkPrefix . $href; 1069 | } 1070 | $args['href'] = $href; 1071 | if ($text !== null) { 1072 | $args['text'] = $text; 1073 | } 1074 | return $this->anchor($args); 1075 | } 1076 | 1077 | /** 1078 | * Wrapper display computer-code samples 1079 | * 1080 | * @param str $str 1081 | * @return str 1082 | */ 1083 | public function code($str) { 1084 | return '' . str_replace(' ', '  ', nl2br(get::htmlentities($str))) . ''; 1085 | } 1086 | 1087 | /** 1088 | * Will return true if the number passed in is even, false if odd. 1089 | * 1090 | * @param int $number 1091 | * @return boolean 1092 | */ 1093 | public function isEven($number) { 1094 | return (Boolean) ($number % 2 == 0); 1095 | } 1096 | 1097 | /** 1098 | * Internal incrementing integar for the alternator() method 1099 | * @var int 1100 | */ 1101 | private $alternator = 1; 1102 | 1103 | /** 1104 | * Returns an alternating Boolean, useful to generate alternating background colors 1105 | * Eg.: 1106 | * $colors = array(true => 'gray', false => 'white'); 1107 | * echo '
...
'; //gray background 1108 | * echo '
...
'; //white background 1109 | * echo '
...
'; //gray background 1110 | * 1111 | * @return Boolean 1112 | */ 1113 | public function alternator() { 1114 | return $this->isEven(++$this->alternator); 1115 | } 1116 | 1117 | /** 1118 | * Returns a list of notifications if there are any - similar to the Flash feature of Ruby on Rails 1119 | * 1120 | * @param mixed $messages String or an array of strings 1121 | * @param string $class 1122 | * @return string Returns null if there are no notifications to return 1123 | */ 1124 | public function getNotifications($messages, $class = 'errormessage') { 1125 | if (isset($messages) && $messages) { 1126 | return '
' 1127 | . (is_array($messages) ? implode('
', $messages) : $messages) . '
'; 1128 | } 1129 | } 1130 | } 1131 | 1132 | /** 1133 | * Vork form-helper 1134 | */ 1135 | class formHelper { 1136 | /** 1137 | * Internal flag to keep track if a form tag has been opened and not yet closed 1138 | * @var boolean 1139 | */ 1140 | private $_formopen = false; 1141 | 1142 | /** 1143 | * Internal form element counter 1144 | * @var int 1145 | */ 1146 | private $_inputCounter = array(); 1147 | 1148 | /** 1149 | * Converts dynamically-assigned array indecies to use an explicitely defined index 1150 | * 1151 | * @param string $name 1152 | * @return string 1153 | */ 1154 | protected function _indexDynamicArray($name) { 1155 | $dynamicArrayStart = strpos($name, '[]'); 1156 | if ($dynamicArrayStart) { 1157 | $prefix = substr($name, 0, $dynamicArrayStart); 1158 | if (!isset($this->_inputCounter[$prefix])) { 1159 | $this->_inputCounter[$prefix] = -1; 1160 | } 1161 | $name = $prefix . '[' . ++$this->_inputCounter[$prefix] . substr($name, ($dynamicArrayStart + 1)); 1162 | } 1163 | return $name; 1164 | } 1165 | 1166 | /** 1167 | * Form types that do not change value with user input 1168 | * @var array 1169 | */ 1170 | protected $_staticTypes = array('hidden', 'submit', 'button', 'image'); 1171 | 1172 | /** 1173 | * Sets the standard properties available to all input elements in addition to user-defined properties 1174 | * Standard properties are: name, value, class, style, id 1175 | * 1176 | * @param array $args 1177 | * @param array $propertyNames Optional, an array of user-defined properties 1178 | * @return array 1179 | */ 1180 | protected function _getProperties(array $args, array $propertyNames = array()) { 1181 | $method = (isset($this->_formopen['method']) && $this->_formopen['method'] == 'get' ? $_GET : $_POST); 1182 | if (isset($args['name']) && (!isset($args['type']) || !in_array($args['type'], $this->_staticTypes))) { 1183 | $arrayStart = strpos($args['name'], '['); 1184 | if (!$arrayStart) { 1185 | if (isset($method[$args['name']])) { 1186 | $args['value'] = $method[$args['name']]; 1187 | } 1188 | } else { 1189 | $name = $this->_indexDynamicArray($args['name']); 1190 | if (preg_match_all('/\[(.*)\]/', $name, $arrayIndex)) { 1191 | array_shift($arrayIndex); //dump the 0 index element containing full match string 1192 | } 1193 | $name = substr($name, 0, $arrayStart); 1194 | if (isset($method[$name])) { 1195 | $args['value'] = $method[$name]; 1196 | if (!isset($args['type']) || $args['type'] != 'checkbox') { 1197 | foreach ($arrayIndex as $idx) { 1198 | if (isset($args['value'][current($idx)])) { 1199 | $args['value'] = $args['value'][current($idx)]; 1200 | } else { 1201 | unset($args['value']); 1202 | break; 1203 | } 1204 | } 1205 | } 1206 | } 1207 | } 1208 | } 1209 | $return = array(); 1210 | $validProperties = array_merge($propertyNames, array('name', 'value', 'class', 'style', 'id')); 1211 | foreach ($validProperties as $propertyName) { 1212 | if (isset($args[$propertyName])) { 1213 | $return[$propertyName] = $args[$propertyName]; 1214 | } 1215 | } 1216 | return $return; 1217 | } 1218 | 1219 | /** 1220 | * Begins a form 1221 | * Includes a safety mechanism to prevent re-opening an already-open form 1222 | * 1223 | * @param array $args 1224 | * @return string 1225 | */ 1226 | public function getFormOpen(array $args = array()) { 1227 | if (!$this->_formopen) { 1228 | if(!isset($args['method'])) { 1229 | $args['method'] = 'post'; 1230 | } 1231 | 1232 | $this->_formopen = array('id' => (isset($args['id']) ? $args['id'] : true), 1233 | 'method' => $args['method']); 1234 | 1235 | if(!isset($args['action'])) { 1236 | $args['action'] = $_SERVER['REQUEST_URI']; 1237 | } 1238 | 1239 | if (isset($args['legend'])) { 1240 | $legend = $args['legend']; 1241 | unset($args['legend']); 1242 | if (!isset($args['title'])) { 1243 | $args['title'] = $legend; 1244 | } 1245 | } else if (isset($args['title'])) { 1246 | $legend = $args['title']; 1247 | } 1248 | if (isset($args['alert'])) { 1249 | if ($args['alert']) { 1250 | $alert = (is_array($args['alert']) ? implode('
', $args['alert']) : $args['alert']); 1251 | } 1252 | unset($args['alert']); 1253 | } 1254 | $return = '
'; 1255 | if (isset($legend)) { 1256 | $return .= '' . $legend . ''; 1257 | } 1258 | if (isset($alert)) { 1259 | $return .= $this->getErrorMessageContainer((isset($args['id']) ? $args['id'] : 'form'), $alert); 1260 | } 1261 | return $return; 1262 | } else if (DEBUG_MODE) { 1263 | $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - a form is already open'; 1264 | trigger_error($errorMsg, E_USER_NOTICE); 1265 | } 1266 | } 1267 | 1268 | /** 1269 | * Closes a form if one is open 1270 | * 1271 | * @return string 1272 | */ 1273 | public function getFormClose() { 1274 | if ($this->_formopen) { 1275 | $this->_formopen = false; 1276 | return '
'; 1277 | } else if (DEBUG_MODE) { 1278 | $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - there is no open form to close'; 1279 | trigger_error($errorMsg, E_USER_NOTICE); 1280 | } 1281 | } 1282 | 1283 | /** 1284 | * Adds label tags to a form element 1285 | * 1286 | * @param array $args 1287 | * @param str $formElement 1288 | * @return str 1289 | */ 1290 | protected function _getLabel(array $args, $formElement) { 1291 | if (!isset($args['label']) && isset($args['name']) 1292 | && (!isset($args['type']) || !in_array($args['type'], $this->_staticTypes))) { 1293 | $args['label'] = ucfirst($args['name']); 1294 | } 1295 | 1296 | if (isset($args['label'])) { 1297 | $label = get::xhtmlentities($args['label']); 1298 | if (isset($_POST['errors']) && isset($args['name']) && isset($_POST['errors'][$args['name']])) { 1299 | $label .= ' ' . $this->getErrorMessageContainer($args['name'], $_POST['errors'][$args['name']]); 1300 | } 1301 | $labelFirst = (!isset($args['labelFirst']) || $args['labelFirst']); 1302 | if (isset($args['id'])) { 1303 | $label = ''; 1305 | } 1306 | if (isset($args['addBreak']) && $args['addBreak']) { 1307 | $label = ($labelFirst ? $label . '
' : '
' . $label); 1308 | } 1309 | $formElement = ($labelFirst ? $label . $formElement : $formElement . $label); 1310 | if (!isset($args['id'])) { 1311 | $formElement = ''; 1312 | } 1313 | } 1314 | return $formElement; 1315 | } 1316 | 1317 | /** 1318 | * Returns a standardized container to wrap an error message 1319 | * 1320 | * @param string $id 1321 | * @param string $errorMessage Optional, you may want to leave this blank and populate dynamically via JavaScript 1322 | * @return string 1323 | */ 1324 | public function getErrorMessageContainer($id, $errorMessage = '') { 1325 | return '' 1326 | . get::htmlentities($errorMessage) . ''; 1327 | } 1328 | 1329 | /** 1330 | * Used for text, textarea, hidden, password, file, button, image and submit 1331 | * 1332 | * Valid args are any properties valid within an HTML input as well as label 1333 | * 1334 | * @param array $args 1335 | * @return string 1336 | */ 1337 | public function getInput(array $args) { 1338 | $args['type'] = (isset($args['type']) ? $args['type'] : 'text'); 1339 | 1340 | switch ($args['type']) { 1341 | case 'select': 1342 | return $this->getSelect($args); 1343 | break; 1344 | case 'checkbox': 1345 | return $this->getCheckboxes($args); 1346 | break; 1347 | case 'radio': 1348 | return $this->getRadios($args); 1349 | break; 1350 | } 1351 | 1352 | if ($args['type'] == 'textarea' && isset($args['maxlength'])) { 1353 | if (!isset($args['id']) && isset($args['name'])) { 1354 | $args['id'] = $args['name']; 1355 | } 1356 | if (isset($args['id'])) { 1357 | $maxlength = $args['maxlength']; 1358 | } 1359 | unset($args['maxlength']); 1360 | } 1361 | 1362 | if ($args['type'] == 'submit' && !isset($args['class'])) { 1363 | $args['class'] = $args['type']; 1364 | } 1365 | 1366 | $takeFocus = (isset($args['focus']) && $args['focus'] && $args['type'] != 'hidden'); 1367 | if ($takeFocus && !isset($args['id'])) { 1368 | if (isset($args['name'])) { 1369 | $args['id'] = $args['name']; 1370 | } else { 1371 | $takeFocus = false; 1372 | if (DEBUG_MODE) { 1373 | $errorMsg = 'Either name or id is required to use the focus option on a form input'; 1374 | trigger_error($errorMsg, E_USER_NOTICE); 1375 | } 1376 | } 1377 | } 1378 | 1379 | $properties = $this->_getProperties($args, array('type', 'maxlength')); 1380 | 1381 | if ($args['type'] == 'image') { 1382 | $properties['src'] = $args['src']; 1383 | $properties['alt'] = (isset($args['alt']) ? $args['alt'] : ''); 1384 | $optionalProperties = array('height', 'width'); 1385 | foreach ($optionalProperties as $optionalProperty) { 1386 | if (isset($args[$optionalProperty])) { 1387 | $properties[$optionalProperty] = $args[$optionalProperty]; 1388 | } 1389 | } 1390 | } 1391 | 1392 | if ($args['type'] != 'textarea') { 1393 | $return[] = ''; 1394 | } else { 1395 | unset($properties['type']); 1396 | if (isset($properties['value'])) { 1397 | $value = $properties['value']; 1398 | unset($properties['value']); 1399 | } 1400 | if (isset($args['preview']) && $args['preview'] && !isset($properties['id'])) { 1401 | $properties['id'] = 'textarea_' . rand(100, 999); 1402 | } 1403 | $properties['rows'] = (isset($args['rows']) ? $args['rows'] : 13); 1404 | $properties['cols'] = (isset($args['cols']) ? $args['cols'] : 55); 1405 | $return[] = ''; 1418 | if (isset($maxlength) && (!isset($args['validatedInput']) || !$args['validatedInput'])) { 1419 | $return[] = $this->getErrorMessageContainer($properties['id']); 1420 | } 1421 | } 1422 | if (!isset($args['addBreak'])) { 1423 | $args['addBreak'] = true; 1424 | } 1425 | if ($takeFocus) { 1426 | $html = get::helper('html'); 1427 | $return[] = $html->jsInline($html->jsTools(true) . 'dom("' . $args['id'] . '").focus();'); 1428 | } 1429 | if (isset($args['preview']) && $args['preview']) { 1430 | $js = 'document.writeln(\'
' 1431 | . '
' 1432 | . '
\');' . PHP_EOL 1433 | . 'if (dom("livepreview_' . $properties['id'] . '")) {' . PHP_EOL 1434 | . ' var updateLivePreview_' . $properties['id'] . ' = ' 1435 | . 'function() {dom("livepreview_' . $properties['id'] . '").innerHTML = ' 1436 | . 'dom("' . $properties['id'] . '").value};' . PHP_EOL 1437 | . ' dom("' . $properties['id'] . '").onkeyup = updateLivePreview_' . $properties['id'] . ';' 1438 | . ' updateLivePreview_' . $properties['id'] . '();' . PHP_EOL 1439 | . '}'; 1440 | if (!isset($html)) { 1441 | $html = get::helper('html'); 1442 | } 1443 | $return[] = $html->jsInline($html->jsTools(true) . $js); 1444 | } 1445 | return $this->_getLabel($args, implode($return)); 1446 | } 1447 | 1448 | /** 1449 | * Returns a form select element 1450 | * 1451 | * $args = array( 1452 | * 'name' => '', 1453 | * 'multiple' => true, 1454 | * 'leadingOptions' => array(), 1455 | * 'optgroups' => array('group 1' => array('label' => 'g1o1', 'value' => 'grp 1 opt 1'), 1456 | * 'group 2' => array(),), 1457 | * 'options' => array('value1' => 'text1', 'value2' => 'text2', 'value3' => 'text3'), 1458 | * 'value' => array('value2', 'value3') //if (multiple==false) 'value' => (str) 'value3' 1459 | * ); 1460 | * 1461 | * @param array $args 1462 | * @return str 1463 | */ 1464 | public function getSelect(array $args) { 1465 | if (!isset($args['id'])) { 1466 | $args['id'] = $args['name']; 1467 | } 1468 | if (isset($args['multiple']) && $args['multiple']) { 1469 | $args['multiple'] = 'multiple'; 1470 | if (substr($args['name'], -2) != '[]') { 1471 | $args['name'] .= '[]'; 1472 | } 1473 | } 1474 | $properties = $this->_getProperties($args, array('multiple')); 1475 | $values = (isset($properties['value']) ? $properties['value'] : null); 1476 | unset($properties['value']); 1477 | if (!is_array($values)) { 1478 | $values = ($values != '' ? array($values) : array()); 1479 | } 1480 | $return = ''; 1528 | if (!isset($args['addBreak'])) { 1529 | $args['addBreak'] = true; 1530 | } 1531 | $return = $this->_getLabel($args, $return); 1532 | if (isset($args['error'])) { 1533 | $return .= $this->getErrorMessageContainer($args['id'], '
' . $args['error']); 1534 | } 1535 | return $return; 1536 | } 1537 | 1538 | /** 1539 | * Cache containing individual radio or checkbox elements in an array 1540 | * @var array 1541 | */ 1542 | public $radios = array(), $checkboxes = array(); 1543 | 1544 | /** 1545 | * Returns a set of radio form elements 1546 | * 1547 | * array( 1548 | * 'name' => '', 1549 | * 'value' => '', 1550 | * 'id' => '', 1551 | * 'legend' => '', 1552 | * 'options' => array('value1' => 'text1', 'value2' => 'text2', 'value3' => 'text3'), 1553 | * 'options' => array('text1', 'text2', 'text3'), //also acceptable (cannot do half this, half above syntax) 1554 | * ) 1555 | * 1556 | * @param array $args 1557 | * @return str 1558 | */ 1559 | public function getRadios(array $args) { 1560 | $id = (isset($args['id']) ? $args['id'] : $args['name']); 1561 | $properties = $this->_getProperties($args); 1562 | if (isset($properties['value'])) { 1563 | $checked = $properties['value']; 1564 | unset($properties['value']); 1565 | } 1566 | $properties['type'] = (isset($args['type']) ? $args['type'] : 'radio'); 1567 | $useValues = (key($args['options']) !== 0 || (isset($args['useValue']) && $args['useValue'])); 1568 | foreach ($args['options'] as $value => $text) { 1569 | if (!$useValues) { 1570 | $value = $text; 1571 | } 1572 | $properties['id'] = $id . '_' . preg_replace('/\W/', '', $value); 1573 | $properties['value'] = $value; 1574 | if (isset($checked) && 1575 | ((($properties['type'] == 'radio' || !is_array($checked)) && $value == $checked) 1576 | || ($properties['type'] == 'checkbox' && is_array($checked) && in_array($value, $checked)))) { 1577 | $properties['checked'] = 'checked'; 1578 | $rowClass = (!isset($properties['class']) ? 'checked' : $properties['class'] . ' checked'); 1579 | } 1580 | $labelFirst = (isset($args['labelFirst']) ? $args['labelFirst'] : false); 1581 | $labelArgs = array('label' => $text, 'id' => $properties['id'], 'labelFirst' => $labelFirst); 1582 | $input = ''; 1583 | $row = $this->_getLabel($labelArgs, $input); 1584 | if (isset($rowClass)) { 1585 | $row = '' . $row . ''; 1586 | } 1587 | $radios[] = $row; 1588 | unset($properties['checked'], $rowClass); 1589 | } 1590 | $this->{$properties['type'] == 'radio' ? 'radios' : 'checkboxes'} = $radios; 1591 | $break = (!isset($args['optionBreak']) ? '
' : $args['optionBreak']); 1592 | $addFieldset = (isset($args['addFieldset']) ? $args['addFieldset'] 1593 | : ((isset($args['label']) && $args['label']) || count($args['options']) > 1)); 1594 | if ($addFieldset) { 1595 | $return = '
'; 1596 | if (isset($args['label'])) { 1597 | $return .= '' . get::htmlentities($args['label']) . ''; 1598 | } 1599 | $return .= implode($break, $radios) . '
'; 1600 | } else { 1601 | $return = implode($break, $radios); 1602 | } 1603 | if (isset($_POST['errors']) && isset($_POST['errors'][$id])) { 1604 | $return = $this->getErrorMessageContainer($id, $_POST['errors'][$id]) . $return; 1605 | } 1606 | return $return; 1607 | } 1608 | 1609 | /** 1610 | * Returns a set of checkbox form elements 1611 | * 1612 | * This method essentially extends the getRadios method and uses an identical signature except 1613 | * that $args['value'] can also accept an array of values to be checked. 1614 | * 1615 | * @param array $args 1616 | * @return str 1617 | */ 1618 | public function getCheckboxes(array $args) { 1619 | $args['type'] = 'checkbox'; 1620 | if (isset($args['value']) && !is_array($args['value'])) { 1621 | $args['value'] = array($args['value']); 1622 | } 1623 | $nameParts = explode('[', $args['name']); 1624 | if (!isset($args['id'])) { 1625 | $args['id'] = $nameParts[0]; 1626 | } 1627 | if (!isset($nameParts[1]) && count($args['options']) > 1) { 1628 | $args['name'] .= '[]'; 1629 | } 1630 | return $this->getRadios($args); 1631 | } 1632 | } 1633 | 1634 | /** 1635 | * phpMoAdmin specific functionality 1636 | */ 1637 | class phpMoAdmin { 1638 | /** 1639 | * Sets the depth limit for phpMoAdmin::getArrayKeys (and prevents an endless loop with self-referencing objects) 1640 | */ 1641 | const DRILL_DOWN_DEPTH_LIMIT = 8; 1642 | 1643 | /** 1644 | * Retrieves all the keys & subkeys of an array recursively drilling down 1645 | * 1646 | * @param array $array 1647 | * @param string $path 1648 | * @param int $drillDownDepthCount 1649 | * @return array 1650 | */ 1651 | public static function getArrayKeys(array $array, $path = '', $drillDownDepthCount = 0) { 1652 | $return = array(); 1653 | if ($drillDownDepthCount) { 1654 | $path .= '.'; 1655 | } 1656 | if (++$drillDownDepthCount < self::DRILL_DOWN_DEPTH_LIMIT) { 1657 | foreach ($array as $key => $val) { 1658 | $return[$id] = $id = $path . $key; 1659 | if (is_array($val)) { 1660 | $return = array_merge($return, self::getArrayKeys($val, $id, $drillDownDepthCount)); 1661 | } 1662 | } 1663 | } 1664 | return $return; 1665 | } 1666 | 1667 | /** 1668 | * Strip slashes recursively - used only when magic quotes is enabled (this reverses magic quotes) 1669 | * 1670 | * @param mixed $val 1671 | * @return mixed 1672 | */ 1673 | public static function stripslashes($val) { 1674 | return (is_array($val) ? array_map(array('self', 'stripslashes'), $val) : stripslashes($val)); 1675 | } 1676 | } 1677 | 1678 | /** 1679 | * phpMoAdmin bootstrap 1680 | */ 1681 | session_start(); 1682 | if (get_magic_quotes_gpc()) { 1683 | $_GET = phpMoAdmin::stripslashes($_GET); 1684 | $_POST = phpMoAdmin::stripslashes($_POST); 1685 | } 1686 | 1687 | if (!isset($_GET['db'])) { 1688 | $_GET['db'] = 'admin'; 1689 | } else if (strpos($_GET['db'], '.') !== false) { 1690 | $_GET['db'] = $_GET['newdb']; 1691 | } 1692 | try { 1693 | moadminComponent::$model = new moadminModel($_GET['db']); 1694 | } catch(Exception $e) { 1695 | echo $e; 1696 | exit(0); 1697 | } 1698 | $html = get::helper('html'); 1699 | $form = new formHelper; 1700 | $mo = new moadminComponent; 1701 | 1702 | /** 1703 | * phpMoAdmin front-end view-element 1704 | */ 1705 | $headerArgs['title'] = (isset($_GET['action']) ? 'phpMoAdmin - ' . get::htmlentities($_GET['action']) : 'phpMoAdmin'); 1706 | if (THEME != 'classic') { 1707 | $headerArgs['jqueryTheme'] = (in_array(THEME, array('swanky-purse', 'trontastic')) ? THEME : 'trontastic'); 1708 | } 1709 | $headerArgs['cssInline'] = ' 1710 | /* reset */ 1711 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, 1712 | big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, 1713 | center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { 1714 | margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent;} 1715 | input, textarea {margin: 0; padding: 0;} 1716 | body {line-height: 1;} 1717 | blockquote, q {quotes: none;} 1718 | blockquote:before, blockquote:after, q:before, q:after {content: ""; content: none;} 1719 | :focus {outline: 0;} 1720 | ins {text-decoration: none;} 1721 | del {text-decoration: line-through;} 1722 | table {border-collapse: collapse; border-spacing: 0;} 1723 | 1724 | html{color:#000;} 1725 | caption,th{text-align:left;} 1726 | h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;} 1727 | abbr,acronym{font-variant:normal;} 1728 | sup{vertical-align:text-top;} 1729 | sub{vertical-align:text-bottom;} 1730 | input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;} 1731 | input,textarea,select{*font-size:100%;} 1732 | legend{color:#000;} 1733 | 1734 | /* \*/ html, body{height:100%;} /* */ 1735 | 1736 | /* initialize */ 1737 | html {background: #74736d;} 1738 | body {margin: auto; width: 990px; font-family: "Arial"; font-size: small; background: #000000; color: #ffffff;} 1739 | #bodycontent {padding: 10px; border: 0px solid;} 1740 | textarea {width: 640px; height: 70px;} 1741 | a, .textLink {text-decoration: none; color: #96f226; font-weight: bold;} 1742 | a:hover, .textLink:hover {text-decoration: underline; color: #9fda58;} 1743 | a:hover pre, h1 a:hover {text-decoration: none;} 1744 | h1, h2, h3, h4 {margin-bottom: 3px;} 1745 | h1, h2 {margin-left: -1px;} 1746 | h1 {font-family: "Arial Black"; font-size: 27px; color: #b8ec79;} 1747 | h1.midpageh1 {margin-top: 10px;} 1748 | h2 {font-size: large; font-weight: bold; margin-top: 10px; color: #660000;} 1749 | h3 {font-weight: bold; color: #687d1c;} 1750 | h4 {font-weight: bold; color: #10478b;} 1751 | p {margin-bottom: 10px; line-height: 1.75;} 1752 | li {line-height: 1.5; margin-left: 15px;} 1753 | .errormessage {color: #990000; font-weight: bold; background: #ffffff; border: 1px solid #ff0000; padding: 2px;} 1754 | .rownumber {float: right; padding: 0px 5px 0px 5px; border-left: 1px dotted; border-bottom: 1px dotted; color: #ffffff; 1755 | margin-top: 4px; margin-right: -1px;} 1756 | .ui-widget-header .rownumber {margin-top: 2px; margin-right: 0px;} 1757 | pre {border: 1px solid; margin: 1px; padding-left: 5px;} 1758 | li .ui-widget-content {margin: 1px 1px 3px 1px;} 1759 | #moadminlogo {color: #96f226; border: 0px solid; padding-left: 10px; font-size: 4px!important; 1760 | width: 265px; height: 63px; overflow: hidden;}'; 1761 | 1762 | switch (THEME) { 1763 | case 'swanky-purse': 1764 | $headerArgs['cssInline'] .= ' 1765 | html {background: #261803;} 1766 | h1, .rownumber {color: #baaa5a;} 1767 | body {background: #4c3a1d url(http://jquery-ui.googlecode.com/svn/tags/1.7.2/themes/swanky-purse/images/ui-bg_diamond_25_675423_10x8.png) 50% 50% repeat;} 1768 | #moadminlogo {color: #baaa5a;} 1769 | li .ui-widget-header {margin: 0px 1px 0px 1px;} 1770 | .ui-widget-header .rownumber {margin-top: 2px; margin-right: -1px;}'; 1771 | break; 1772 | case 'classic': 1773 | $headerArgs['cssInline'] .= ' 1774 | html, .ui-widget-header, button {background: #ccc78c;} 1775 | .ui-widget-content, input.ui-state-hover {background: #edf2ed;} 1776 | h1, .rownumber {color: #796f54;} 1777 | body {background: #ffffcc; color: #000000;} 1778 | #bodycontent {background: #ffffcc;} 1779 | #moadminlogo, button {color: #bb0022;} 1780 | a, .textLink {color: #990000;} 1781 | a:hover, .textLink:hover {color: #7987ae;} 1782 | li .ui-widget-header {margin: 0px 1px 0px 1px;} 1783 | .rownumber {margin-top: 2px; margin-right: 0px;} 1784 | .ui-dialog {border: 3px outset;} 1785 | .ui-dialog .ui-dialog-titlebar {padding: 3px; margin: 1px; border: 3px ridge;} 1786 | .ui-dialog #confirm {padding: 10px;} 1787 | .ui-dialog .ui-icon-closethick, .ui-dialog button {float: right; margin: 4px;} 1788 | .ui-dialog .ui-icon-closethick {margin-top: -13px;} 1789 | body:first-of-type .ui-dialog .ui-icon-closethick {margin-top: -2px;} /*Chrome/Safari*/ 1790 | .ui-resizable { position: relative;} 1791 | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} 1792 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } 1793 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } 1794 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } 1795 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } 1796 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } 1797 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } 1798 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } 1799 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } 1800 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}'; 1801 | break; 1802 | } 1803 | echo $html->header($headerArgs); 1804 | 1805 | echo $html->jsLoad(array('jquery', 'jqueryui')); 1806 | $baseUrl = $_SERVER['SCRIPT_NAME']; 1807 | 1808 | $db = (isset($_GET['db']) ? $_GET['db'] : (isset($_POST['db']) ? $_POST['db'] : get::$config->DB_NAME)); 1809 | $dbUrl = urlencode($db); 1810 | 1811 | $phpmoadmin = ''; 1829 | echo '

' 1830 | . $html->link('http://www.phpmoadmin.com', $phpmoadmin, array('title' => 'phpMoAdmin')) . '

'; 1831 | 1832 | if (isset($accessControl) && !isset($_SESSION['user'])) { 1833 | if (isset($_POST['username'])) { 1834 | $_POST = array_map('trim', $_POST); 1835 | if (isset($accessControl[$_POST['username']]) && $accessControl[$_POST['username']] == $_POST['password']) { 1836 | $_SESSION['user'] = $_POST['username']; 1837 | } else { 1838 | $_POST['errors']['username'] = 'Incorrect username or password'; 1839 | } 1840 | } 1841 | if (!isset($_SESSION['user'])) { 1842 | echo $form->getFormOpen(); 1843 | echo $html->div($form->getInput(array('name' => 'username', 'focus' => true))); 1844 | echo $html->div($form->getInput(array('type' => 'password', 'name' => 'password'))); 1845 | echo $html->div($form->getInput(array('type' => 'submit', 'value' => 'Login', 'class' => 'ui-state-hover'))); 1846 | echo $form->getFormClose(); 1847 | exit(0); 1848 | } 1849 | } 1850 | 1851 | echo '
'; 1852 | $formArgs = array('method' => 'get'); 1853 | if (isset($mo->mongo['repairDb'])) { 1854 | $formArgs['alert'] = (isset($mo->mongo['repairDb']['ok']) && $mo->mongo['repairDb']['ok'] 1855 | ? 'Database has been repaired and compacted' : 'Database could not be repaired'); 1856 | } 1857 | echo $form->getFormOpen($formArgs); 1858 | echo $html->div($form->getSelect(array('name' => 'db', 'options' => $mo->mongo['dbs'], 'label' => '', 'value' => $db, 1859 | 'addBreak' => false)) 1860 | . $form->getInput(array('type' => 'submit', 'value' => 'Change database', 'class' => 'ui-state-hover')) 1861 | . ' ' . get::htmlentities($db) 1862 | . ' [' . $html->link("javascript: mo.repairDatabase('" . get::htmlentities($db) 1863 | . "'); void(0);", 'repair database') . '] [' . $html->link("javascript: mo.dropDatabase('" 1864 | . get::htmlentities($db) . "'); void(0);", 'drop database') . ']'); 1865 | echo $form->getFormClose() . $html->jsInline('var mo = {} 1866 | mo.urlEncode = function(str) { 1867 | return escape(str)' 1868 | . '.replace(/\+/g, "%2B").replace(/%20/g, "+").replace(/\*/g, "%2A").replace(/\//g, "%2F").replace(/@/g, "%40"); 1869 | } 1870 | mo.repairDatabase = function(db) { 1871 | mo.confirm("Are you sure that you want to repair and compact the " + db + " database?", function() { 1872 | window.location.replace("' . $baseUrl . '?db=' . $dbUrl . '&action=repairDb"); 1873 | }); 1874 | } 1875 | mo.dropDatabase = function(db) { 1876 | mo.confirm("Are you sure that you want to drop the " + db + " database?", function() { 1877 | mo.confirm("All the collections in the " + db + " database will be lost along with all the data within them!' 1878 | . '\n\nAre you 100% sure that you want to drop this database?' 1879 | . '\n\nLast chance to cancel!", function() { 1880 | window.location.replace("' . $baseUrl . '?db=' . $dbUrl . '&action=dropDb"); 1881 | }); 1882 | }); 1883 | } 1884 | $("select[name=db]").prepend(\'\')' 1885 | . '.after(\'\').change(function() { 1886 | ($(this).val() == "new.database" ? $("input[name=newdb]").show() : $("input[name=newdb]").hide()); 1887 | }); 1888 | mo.confirm = function(dialog, func, title) { 1889 | if (typeof title == "undefined") { 1890 | title = "Please confirm:"; 1891 | } 1892 | if (!$("#confirm").length) { 1893 | $("#dbcollnav").append(\'\'); 1894 | } 1895 | mo.userFunc = func; //overcomes JS scope issues 1896 | $("#confirm").html(dialog).attr("title", title).dialog({modal: true, buttons: { 1897 | "Yes": function() {$(this).dialog("close"); mo.userFunc();}, 1898 | Cancel: function() {$(this).dialog("close");} 1899 | }}).dialog("open"); 1900 | } 1901 | '); 1902 | 1903 | if (isset($_GET['collection'])) { 1904 | $collection = get::htmlentities($_GET['collection']); 1905 | unset($_GET['collection']); 1906 | } 1907 | if (isset($mo->mongo['listCollections'])) { 1908 | echo '
'; 1909 | 1910 | echo $form->getFormOpen(array('method' => 'get')); 1911 | echo $html->div($form->getInput(array('name' => 'collection', 'label' => '', 'addBreak' => false)) 1912 | . $form->getInput(array('name' => 'action', 'type' => 'hidden', 'value' => 'createCollection')) 1913 | . $form->getInput(array('type' => 'submit', 'value' => 'Add new collection', 'class' => 'ui-state-hover')) 1914 | . $form->getInput(array('name' => 'db', 'value' => get::htmlentities($db), 'type' => 'hidden')) 1915 | . '       [' . $html->link($baseUrl . '?action=getStats', 'stats') . ']'); 1916 | echo $form->getFormClose(); 1917 | 1918 | if (!$mo->mongo['listCollections']) { 1919 | echo $html->div('No collections exist'); 1920 | } else { 1921 | echo '
    '; 1922 | foreach ($mo->mongo['listCollections'] as $col => $rowCount) { 1923 | echo $html->li($html->link($baseUrl . '?db=' 1924 | . $dbUrl . '&action=listRows&collection=' . urlencode($col), $col) 1925 | . ' (' . number_format($rowCount) . ')'); 1926 | } 1927 | echo '
'; 1928 | echo $html->jsInline('mo.collectionDrop = function(collection) { 1929 | mo.confirm.collection = collection; 1930 | mo.confirm("Are you sure that you want to drop " + collection + "?", 1931 | function() { 1932 | mo.confirm("All the data in the " + mo.confirm.collection + " collection will be lost;' 1933 | . ' are you 100% sure that you want to drop it?\n\nLast chance to cancel!", 1934 | function() { 1935 | window.location.replace("' . $baseUrl . '?db=' . $dbUrl 1936 | . '&action=dropCollection&collection=" + mo.urlEncode(mo.confirm.collection)); 1937 | } 1938 | ); 1939 | } 1940 | ); 1941 | } 1942 | $(document).ready(function() { 1943 | $("#mongo_collections li").each(function() { 1944 | $(this).prepend("[X] "); 1946 | }); 1947 | }); 1948 | '); 1949 | } 1950 | $url = $baseUrl . '?' . http_build_query($_GET); 1951 | if (isset($collection)) { 1952 | $url .= '&collection=' . urlencode($collection); 1953 | } 1954 | echo $form->getFormOpen(array('action' => $url, 'style' => 'width: 80px; height: 20px;')) 1955 | . $form->getInput(array('name' => 'limit', 'value' => $_SESSION['limit'], 'label' => '', 'addBreak' => false, 1956 | 'style' => 'width: 40px;')) 1957 | . $form->getInput(array('type' => 'submit', 'value' => 'limit', 'class' => 'ui-state-hover')) 1958 | . $form->getFormClose(); 1959 | echo '
'; 1960 | } 1961 | echo '
'; //end of dbcollnav 1962 | $dbcollnavJs = '$("#dbcollnav").after(\'[Show Database & Collection selection]\').hide();'; 1964 | if (isset($mo->mongo['listRows'])) { 1965 | echo $html->h1($collection); 1966 | if (isset($mo->mongo['listIndexes'])) { 1967 | echo '
'); void(0);" 1976 | . '">[Add another index field]' 1977 | . $form->getRadios(array('name' => 'unique', 'options' => array('Index', 'Unique'), 'value' => 'Index')) 1978 | . $form->getInput(array('type' => 'submit', 'value' => 'Add new index', 'class' => 'ui-state-hover')) 1979 | . $form->getInput(array('name' => 'action', 'type' => 'hidden', 'value' => 'ensureIndex')) 1980 | . $form->getInput(array('name' => 'db', 'value' => get::htmlentities($db), 'type' => 'hidden')) 1981 | . $form->getInput(array('name' => 'collection', 'value' => $collection, 'type' => 'hidden')) 1982 | . $form->getFormClose(); 1983 | foreach ($mo->mongo['listIndexes'] as $indexArray) { 1984 | $index = ''; 1985 | foreach ($indexArray['key'] as $key => $direction) { 1986 | $index .= (!$index ? $key : ', ' . $key); 1987 | if (!is_object($direction)) { 1988 | $index .= ' [' . ($direction == -1 ? 'desc' : 'asc') . ']'; 1989 | } 1990 | } 1991 | if (isset($indexArray['unique']) && $indexArray['unique']) { 1992 | $index .= ' [unique]'; 1993 | } 1994 | if (key($indexArray['key']) != '_id' || count($indexArray['key']) !== 1) { 1995 | $index = '[' . $html->link($baseUrl . '?db=' . $dbUrl . '&collection=' . urlencode($collection) 1996 | . '&action=deleteIndex&index=' 1997 | . serialize($indexArray['key']), 'X', array('title' => 'Drop Index', 1998 | 'onclick' => "mo.confirm.href=this.href; " 1999 | . "mo.confirm('Are you sure that you want to drop this index?', " 2000 | . "function() {window.location.replace(mo.confirm.href);}); return false;") 2001 | ) . '] ' 2002 | . $index; 2003 | } 2004 | echo '
  • ' . $index . '
  • '; 2005 | } 2006 | echo ''; 2007 | } 2008 | $objCount = $mo->mongo['listRows']->count(true); //count of rows returned 2009 | $paginator = number_format($mo->mongo['count']) . ' objects'; //count of rows in collection 2010 | if ($mo->mongo['count'] != $objCount) { 2011 | $skip = (isset($_GET['skip']) ? $_GET['skip'] : 0); 2012 | $get = $_GET; 2013 | unset($get['skip']); 2014 | $url = $baseUrl . '?' . http_build_query($get) . '&collection=' . urlencode($collection) . '&skip='; 2015 | $paginator = number_format($skip + 1) . '-' . number_format(min($skip + $objCount, $mo->mongo['count'])) 2016 | . ' of ' . $paginator; 2017 | if ($skip) { //back 2018 | $paginator = addslashes($html->link($url . max($skip - $objCount, 0), '<<<')) . ' ' . $paginator; 2019 | } 2020 | if ($mo->mongo['count'] > ($objCount + $skip)) { //forward 2021 | $paginator .= ' ' . addslashes($html->link($url . ($skip + $objCount), '>>>')); 2022 | } 2023 | } 2024 | echo $html->jsInline('mo.indexCount = 1; 2025 | $(document).ready(function() { 2026 | $("#mongo_rows").prepend("
    ' 2027 | . '[Compact] ' 2029 | . '[Uniform] ' 2031 | . '[Full]' 2033 | . '
    ' . $paginator . '
    "); 2034 | }); 2035 | mo.removeObject = function(_id, idType) { 2036 | mo.confirm("Are you sure that you want to delete this " + _id + " object?", function() { 2037 | window.location.replace("' . $baseUrl . '?db=' . $dbUrl . '&collection=' . urlencode($collection) 2038 | . '&action=removeObject&_id=" + mo.urlEncode(_id) + "&idtype=" + idType); 2039 | }); 2040 | } 2041 | ' . $dbcollnavJs); 2042 | 2043 | echo '
    '; 2044 | if ($mo->mongo['colKeys']) { 2045 | echo $form->getFormOpen(); 2046 | } 2047 | echo '[' . $html->link($baseUrl . '?db=' . $dbUrl . '&collection=' . urlencode($collection) . '&action=editObject', 2048 | 'Insert New Object') . '] '; 2049 | if (isset($index)) { 2050 | echo '[Show Indexes] '; 2051 | } 2052 | if ($mo->mongo['colKeys']) { 2053 | $sort = array('name' => 'sort', 'id' => 'sort', 'options' => $mo->mongo['colKeys'], 'label' => '', 2054 | 'addBreak' => false); 2055 | $sortdir = array('name' => 'sortdir', 'id' => 'sortdir', 'options' => array(1 => 'asc', -1 => 'desc'), 2056 | 'label' => '', 'addBreak' => false); 2057 | if (isset($_GET['sort'])) { 2058 | $sort['value'] = key($_GET['sort']); 2059 | $sortdir['value'] = current($_GET['sort']); 2060 | } 2061 | echo $form->getSelect($sort) . $form->getSelect($sortdir) . ' ' 2062 | . $html->link("javascript: document.location='" . $baseUrl . '?db=' . $dbUrl . '&collection=' 2063 | . urlencode($collection) . "&action=listRows&sort[' + document.getElementById('sort').value + ']='" 2064 | . " + document.getElementById('sortdir').value; void(0);", 'Sort', 2065 | array('class' => 'ui-state-hover', 'style' => 'padding: 3px 8px 3px 8px;')); 2066 | echo $form->getFormClose(); 2067 | } 2068 | 2069 | echo '
      '; 2070 | $rowCount = (!isset($skip) ? 0 : $skip); 2071 | $isChunksTable = (substr($collection, -7) == '.chunks'); 2072 | if ($isChunksTable) { 2073 | $chunkUrl = $baseUrl . '?db=' . $dbUrl . '&action=listRows&collection=' . urlencode(substr($collection, 0, -7)) 2074 | . '.files#'; 2075 | } 2076 | foreach ($mo->mongo['listRows'] as $row) { 2077 | $showEdit = true; 2078 | $id = $idString = $row['_id']; 2079 | if (is_object($idString)) { 2080 | $idString = '(' . get_class($idString) . ') ' . $idString; 2081 | $idForUrl = serialize($id); 2082 | } else { 2083 | $idForUrl = urlencode($id); 2084 | } 2085 | $idType = gettype($row['_id']); 2086 | $idDepth = 0; //protection against endless looping 2087 | while (is_array($id) && ++$idDepth < 10) { 2088 | $id = current($id); 2089 | $idString .= '->' . $id; 2090 | } 2091 | if ($isChunksTable && isset($row['data']) && is_object($row['data']) 2092 | && get_class($row['data']) == 'MongoBinData') { 2093 | $showEdit = false; 2094 | $row['data'] = $html->link($chunkUrl . $row['files_id'], 'MongoBinData Object', 2095 | array('class' => 'MoAdmin_Reference')); 2096 | } 2097 | $data = explode("\n", substr(print_r($row, true), 8, -2)); 2098 | $binData = 0; 2099 | foreach ($data as $id => $rowData) { 2100 | $raw = trim($rowData); 2101 | if ($binData) { 2102 | if (strpos($rowData, '] => ') !== false) { 2103 | ++$binData; 2104 | } 2105 | unset($data[$id]); 2106 | continue; 2107 | } 2108 | 2109 | if ($raw === '') { 2110 | unset($data[$id]); 2111 | } else if ($raw === '(') { //one-true-brace 2112 | $data[($id - 1)] .= ' ('; 2113 | unset($data[$id]); 2114 | } else { 2115 | if (strpos($data[$id], 'MongoBinData Object') !== false) { 2116 | $showEdit = false; 2117 | $binData = -2; 2118 | } 2119 | $data[$id] = str_replace(' ', ' ', (substr($rowData, 0, 4) === ' ' ? substr($rowData, 4) 2120 | : $rowData)); 2121 | if ($raw === ')') { 2122 | $data[$id] = substr($data[$id], 4); 2123 | } 2124 | if (strpos($data[$id], 'MoAdmin_Reference') === false) { 2125 | $data[$id] = get::htmlentities($data[$id]); 2126 | } 2127 | } 2128 | } 2129 | echo $html->li('
      ' 2131 | . '[' . $html->link("javascript: mo.removeObject('" . $idForUrl . "', '" . $idType 2132 | . "'); void(0);", 'X', array('title' => 'Delete')) . '] ' 2133 | . ($showEdit ? '[' . $html->link($baseUrl . '?db=' . $dbUrl . '&collection=' . urlencode($collection) 2134 | . '&action=editObject&_id=' . $idForUrl . '&idtype=' . $idType, 'E', array('title' => 'Edit')) . '] ' 2135 | : ' [N/A] ') 2136 | . $idString . '
      ' . number_format(++$rowCount) . '
      '
      2137 |            . wordwrap(implode("\n", $data), 136, "\n", true) . '
      '); 2138 | } 2139 | echo '
    '; 2140 | if (!isset($idString)) { 2141 | echo '
    No records in this collection
    '; 2142 | } 2143 | echo '
    '; 2144 | } else if (isset($mo->mongo['editObject'])) { 2145 | echo $form->getFormOpen(array('action' => $baseUrl . '?db=' . $dbUrl . '&collection=' . urlencode($collection))); 2146 | if (isset($_GET['_id']) && $_GET['_id'] && $_GET['idtype'] == 'object') { 2147 | $_GET['_id'] = unserialize($_GET['_id']); 2148 | } 2149 | echo $html->h1(isset($_GET['_id']) && $_GET['_id'] ? get::htmlentities($_GET['_id']) : '[New Object]'); 2150 | echo $html->div($form->getInput(array('type' => 'submit', 'value' => 'Save Changes', 'class' => 'ui-state-hover'))); 2151 | $textarea = array('name' => 'object', 'label' => '', 'type' => 'textarea'); 2152 | $textarea['value'] = ($mo->mongo['editObject'] !== '' ? var_export($mo->mongo['editObject'], true) 2153 | : 'array (' . PHP_EOL . PHP_EOL . ')'); 2154 | //MongoID as _id 2155 | $textarea['value'] = preg_replace('/\'_id\' => \s*MongoId::__set_state\(array\(\s*\)\)/', '\'_id\' => new MongoId("' 2156 | . (isset($_GET['_id']) ? $_GET['_id'] : '') . '")', $textarea['value']); 2157 | //MongoID in all other occurrences, original ID is not maintained 2158 | $textarea['value'] = preg_replace('/MongoId::__set_state\(array\(\s*\)\)/', 'new MongoId()', $textarea['value']); 2159 | //MongoDate 2160 | $textarea['value'] = preg_replace('/MongoDate::__set_state\(array\(\s*\'sec\' => (\d+),\s*\'usec\' => \d+,\s*\)\)/m', 2161 | 'new MongoDate($1)', $textarea['value']); 2162 | echo $html->div($form->getInput($textarea) 2163 | . $form->getInput(array('name' => 'action', 'type' => 'hidden', 'value' => 'editObject'))); 2164 | echo $html->div($form->getInput(array('name' => 'db', 'value' => get::htmlentities($db), 'type' => 'hidden')) 2165 | . $form->getInput(array('type' => 'submit', 'value' => 'Save Changes', 'class' => 'ui-state-hover'))); 2166 | echo $form->getFormClose(); 2167 | echo $html->jsInline('$("textarea[name=object]").css({"min-width": "750px", "max-width": "1250px", ' 2168 | . '"min-height": "450px", "max-height": "2000px", "width": "auto", "height": "auto"}).resizable(); 2169 | ' . $dbcollnavJs); 2170 | } else if (isset($mo->mongo['getStats'])) { 2171 | echo ''; 2186 | } 2187 | echo ''; //end of bodycontent 2188 | 2189 | echo $html->footer(); -------------------------------------------------------------------------------- /my_enginx_config/var/www/nginx-default/reload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reload 5 | 89 | 90 | 91 | 92 |
    
    93 | 
    94 | 
    95 | 
    96 | 
    
    
    --------------------------------------------------------------------------------
    /nodejs.conf:
    --------------------------------------------------------------------------------
     1 | #!upstart
     2 | description "node.js server"
     3 | author      "shimon doodkin"
     4 | # license: public domain
     5 | 
     6 | start on runlevel [2345]
     7 | stop on runlevel [06]
     8 | 
     9 | 
    10 | script
    11 |     export HOME="/root"
    12 | 
    13 |     # one of the four lines below might work well:
    14 | 
    15 |     exec sudo -u www-data /bin/bash /var/www/nodejs-mongodb-app/nodejs.sh
    16 | 
    17 |     #exec sudo -u www-data /bin/bash -c 'while true; do /usr/local/bin/node /var/www/server.js 2>&1 >> /var/log/nodejs.log; sleep 1$
    18 |     #exec /usr/local/bin/node /var/www/server.js 2>&1 >> /var/log/nodejs.log
    19 |     #exec sudo -u www-data /usr/local/bin/node /var/www/server.js 2>&1 >> /var/log/nodejs.log
    20 | 
    21 | end script
    22 | 
    23 | # insted of useing monit i did: a shell while true script and used inside the server request loop:
    24 | # try {code} catch(e){sys.puts(e.stack);}
    
    
    --------------------------------------------------------------------------------
    /nodejs.sh:
    --------------------------------------------------------------------------------
     1 | #!/bin/bash
     2 |    
     3 | while true;
     4 |  do 
     5 |  
     6 |   echo starting $(date);
     7 | 
     8 |   script_directory=`dirname "$0"`;
     9 |   cd $script_directory;
    10 |   
    11 |   #touch /var/log/nodejs.log
    12 |   #chmod 777 /var/log/nodejs.log
    13 |   #
    14 |   # echo "bla" > file.txt # replaces file
    15 |   # echo "bla" >> file.txt # appends to file
    16 |   #
    17 |   /usr/local/bin/node server.js $* > /var/log/nodejs.log 2>&1;
    18 | 
    19 |   exit_value="$?" ;
    20 |   echo stopping $(date);
    21 |    
    22 |   if [ "$exit_value" != "0" ]; then 
    23 |    sleep 5;
    24 |   else 
    25 |    sleep 0.5;
    26 |   fi ;
    27 | 
    28 |  done;
    29 | 
    
    
    --------------------------------------------------------------------------------