Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Replace PHP server with a Node app #147

wants to merge 598 commits into from

7 participants


Just creating this pull request for reference, it doesn't need to be merged until it's done.

General Aims (to be updated):

  • Replace the dependancy on PHP with a pure JavaScript application.
  • Retain the current version of the PHP app for easy deployment.

Getting Started:

Install dependancies with npm and create a config.local.json file with any local settings, hopefully they're self explanatory at the moment. eg.

$ npm install
$ cp config.default.json config.local.json
$ $EDITOR config.local.json
$ node lib/app.js

The PHP app will continue to run but you'll need to update the apache config to make public the root directory.

NOTE: I couldn't push this up as next/3/node as you can't have branches using slashes with hierarchical names. ie. no next/3/node if you have next/3.
NOTE TWO: I've removed the GA code from this branch. Be sure to add it back when deploying to production.


* Preview
* Pull title from code
* Auth (user account creation and login)
* PHP authentication
* Upgrade passwords for old accounts
* User ownership of bins
* Logout
* User homepage
- Unit tests
- Docs
- SQLite adapter
* Plain Text
* Blacklist
* Download
* Custom user configs
- Gist
- npm install -g jsbin && jsbin

I can't quite tell where in the code, but the createBin method is escaping the content on the way in to the database - which is bad because a) it means the saved content is different to what the user gave us, but more importantly b) it means that it's double escaped on the way out.

Having trouble replicating though....maybe it was a mix between my old server and your new one...will see if I can replicate...


@remy What do you mean by "escaping"? I wouldn't think either express or the mysql modules would modify the data. We're currently using the connect bodyParser middleware to parse the post body. That would be the first place to look.

I haven't fully implemented the same logic as in the PHP app yet, it's literally throwing the data in and pulling it out. None of the normalising from getCode() is in there yet.


Something definitely saved everything escaped - but I can't be sure when it happened.

Okay, cool but what do you mean by escaped? URL encoded? Escaped quotes? Newlines? What am I looking for? :)


@remy re. the escaped quotes I'm 90% sure this is because the PHP app is storing data with php magic quotes enabled which means all your quotes will be escaped. So you're seeing them in the node app when you view old bins (the PHP app strips them on the way out).

Ideally we should disable magic quotes in the PHP app (it's a stupid feature). Then we'll have to add support for stripping quotes to the node app for older bins :/ or even better go through the database and reformat each code entry.


Re-posted from irc. We should be able to disable this in the .htaccess file by adding:

php_flag magic_quotes_gpc Off

Although I've no idea about general support for the php_flag command on various hosts, I've always had it available.


@remy nah if it's escaped in the database it's not working.


Keep up the great work @aron. +1 for Node backend.

aron and others added some commits
@aron aron Create a sandbox object and pass it into the handlers
This is the start of a re-factor to remove the crazy number of objects
being bound to the request object.
@aron aron Replace req.models with this.models in BinHandler f88fbe5
@aron aron Fix a couple of lint issues 70fa431
@aron aron Replace req.helpers with this.h in BinHandler 29203c4
@aron aron Finally able to stop passing helpers object internally 7d5a01b
@aron aron Replace req.models with this.models in SessionHandler cdf2066
@aron aron Remove remaining req helper objects c79c5a3
@aron aron Remove unneeded code from app and middleware cbc89ee
@aron aron Fix syntax error in SessionHandler 9c38d37
@aron aron Fix a couple more errors in refactoring a0573ac
@aron aron helpers.url() now trims the preceding / from a url 800f2eb
@aron aron Rename "production?" template variable to "is_production" 4fdca13
@aron aron Remove trailing whitespace in index.html 99eec49
@aron aron Fix broken html in password input 6f3f014
@aron aron Tidy up and document error objects 6d0badf
@aron aron Handle JSBin error objects dfb1f83
@remy remy Update package with license c110276
@remy remy Tweak to menu display and added solarize theme c0a6d2d
@remy remy Read the port and override the Fixes #197 baad541
@remy remy Scripts now unrolled for better debugging and development. Order real…
…ly matters and build script moved to grunt.

Requires global install of grunt if using in production, but I guess
local installs will run in development mode by default.
@remy remy Remove hover effect on splitter 56c22f1
@remy remy Support changing theme d10b12d
@remy remy Updates json2 - it had a bug in it originally cd76cc0
@remy remy Starting to link console to main output window. Progress on #178
Still not quite there, but will be!
@remy remy Fixing conflicts 0f53556

@aron Typo?

No, but not a great property name now I look at it today. Will update to this.helpers

aron and others added some commits
@aron aron Fix occurance of req.helpers in BinHandler 762ae48
@aron aron Re-name this.h to this.helpers for better karma e4e3d1c
@remy remy Frickin lint b59452f
@remy remy More progress on #178 - getting console linked to the output panel. bd2843c
@aron aron Add jshint options for the node app cc7834d
@aron aron Add grunt file for the node app
Currently has two useful commands:

    $ grunt lint         # Lints the node codebase
    $ grunt run:<config> # Runs the server with optional config
@aron aron Lint the codebase 665c045
@aron aron Remove custom serve command from Makefile
This has been superceded by "grunt run"
@aron aron Fix grunt run check for config file existance 99f7c0a
@remy remy Little trick/easter egg to enable line numbers 402be7d
@remy remy Named the robot: Dave.
There's not a great reason, but it makes sense in my head.
@remy remy Shuffling logic to allow for new disconnected script loading. 00d72a2
@remy remy Fixed regexp by reseting the last index. ::Sigh:: 21c9b85
@remy remy hasOwnProperty polyfill 24d68ee
@remy remy Slightly better quality image of Dave 5e8a4db
@remy remy Tweak for line numbers 681399d
@aron aron Remove debugger statement 857e80f
@leobalter leobalter Adding QUnit lib in "Testing" group 6e824f3
@remy remy More line number love 84e7e14
@remy remy Merge branch 'feature/node' of into feature/node 8867dbc
@remy remy Moved prep code earlier - seemed to have broken live… 1bfcd38
@remy remy Helper method allEditors 08a1856
@remy remy Font family on input types 8798254
@remy remy Welcome first timers 60c6e3d
@remy remy Codecasting support. Yeah, seriously, that's all it took. 2962c25
@remy remy Code moved to app.js 5961e62
@remy remy Don't render the console is output is visible (as console is then ren…
…dered with live update)
@remy remy Not /that/ useful, but affords me some stats. e32f37b
@remy remy Fixed the order to prevent the update title bug 293c821
@remy remy make sqlite the default for node - NOTE: php version currently not su…
…pported - big ass todo
@remy remy Fixed order of code, helper was being created with production set to …
…false before reading config
@remy remy Disabled helper - it wasn't there to allow for proxying bca1846
@remy remy Fix sqlite version 12b8230
@remy remy Adding static support 3c0f808
@remy remy Fixed Opera icon, and fixed library select not working in FF d618d1e
@remy remy Always select a panel if one is hidden 0af4785
@remy remy Tweak to panel style to highlight focus better c1146e3
@remy remy Fixed preview broken in node app 81beb79
@remy remy Highlight panels that have content 2a040ae
@remy remy Allow user to use permalink /rem/last for easy device testing 57ce5ec
@remy remy Easy urls, plus adding gravatar support like PHP version 51ce867
@remy remy Normalised where the session was set 901be2e
@remy remy Updated todo, and put embed back in f888b27
@remy remy Fixing reading static path for PHP install (hopefully last PHP support) 2e7db2b
@remy remy Updating TODO with misc thoughts 63334dd
@remy remy iPad was wrapping the reg form cff104a
@remy remy Ensuring content is a string when setting d37e625
@remy remy Enable live JS by deafult cad286c
@remy remy Tweak to history selection, and FIXED iOS text focus - yay! fe85191
@remy remy Quietening down the tips for a while 00729d1
@remy remy Don't set focus on the iPad
Would love to test other tablets, but I don't have any just now
@remy remy Nicer hover effect 20ea268
@remy remy Fixed iPad throwing a wobbly, to be fair, I was nuking the CodeMirror…
… object
@remy remy Give mobile mirror to IE7…and not mobile…got figure 20c2ff6
@remy remy Override triggered focus - should fix all iOS views on jsbin 88d9817
@remy remy If logged in, allow the password or email to be changed. f33a399
@remy remy Updated the required field for account update 980c510
@aron aron Now using SessionHandler#setUserSession() consistently 10dd2dc
@aron aron Bail early if no name is provided when loading user d33f13f
@aron aron Implemented a router handler for the /sethome endpoint a52e29a
@aron aron Checking for existence of username before creating account a181c23
@aron aron Implemented the remaining account methods f196a40
@aron aron Using new account route handler ba3281a
@aron aron Add utils.gravatar() for creating gravatar urls c18cd88
@aron aron Pass a gravatar url into the index.html template 025ab3a
@aron aron Only show name error message if name param is provided cc21fda
@aron aron Allow helpers.url() to be called with no argument 41547ac
@aron aron User is now redirected to JSBin home to reset thier password 62ba03e
@aron aron Email is now required on forgot password form bf529ef
@aron aron Add a very simple flash message middleware 106e256
@aron aron Add flash messages to template 946fdd6
@aron aron Show flash messages when requesting email reset 1ea3f7c
@aron aron Remove all instances of NOW() from the sql templates 29bdb84
@aron aron Update SQLite adapter to use sql_templates.json
This is completely untested. Please don't hurt me if it doesn't work!
@aron aron Using utils.inherit() in MySQL adapter 064d1a5
@aron aron Tidy up SQLite adapter a little more 0e83bb3
@aron aron Use utils.inherit() to tidy up SQLite file a3e6ad4
@aron aron Fix the display of the bin url on creation c7d282e
@aron aron Send an error response if unable to render files c52a6eb
@aron aron Update both SQL files for v3 5807bbb
@aron aron Update SQLite adapter to work with sql_templates.json 6f50501
@aron aron Remove sqlite_templates.json. Whoop! 5df51d7
@aron aron Add app.connect() function to allow database connections 95f0b68
@aron aron Fix typo in SessionHandler 4205c0e
@aron aron Update session when email changes 4653997
@aron aron Update Bcrypt module
Requires old version to be removed before updating.
@aron aron Improve SQLite handling of bin defaults 8115538
@aron aron Define the "basepath" app setting 40ad33c
@aron aron Greatly improve how redirects are handled. Closes #198
Referrer is now used by default unless a form specifies an alternative.
@aron aron Add a bind property to package.json 68384f8
@aron aron Ignore all PHP files when creating the npm module c06a477
@aron aron Add a jsbin binary for the npm package 142f9fb
@aron aron Update package.json with commander module ab08807
@aron aron Sort out the port assignment in app.js ed926fa
@aron aron Set default host to localhost:3000
It's for the good of the npm deployment honest.
@aron aron Remove gobo, may he rest in peace 69a6239
@aron aron Keep the SQL in the npm module a81b86f
@aron aron Handle unloaded bins correctly c1089ec
@remy remy Point spike scripts to static server b1d93ba
@remy remy Merge branch 'feature/node' of into feature/node 5b4df8b
@remy remy Don't read the port from the env - because we can't proxy with it 2e411b2
@remy remy Fix error in url method 8ef5a54
@remy remy Reversing @aron's port logic (this broke launching the server behind …
…a proxy)
@remy remy Stupid fix for Firefox
Basically because the element vanishes from under the mouse, the item
the user thought they were clicking on is no longer there, so in the
end, no link is clicked, so nothing happens. This change just defers
the menu from being hidden on the next tick - most importantly: /after/
the click has happened.
@remy remy Fixed heading size in model info boxes 0705c95
@remy remy More TODOs cfce15f
@remy remy Experimenting with tidier urls - not updating the url when panels are…
… shown

Note that if no panel state is found locally, then it should show the
live and any panel with content.
@aron aron Remove incorrect "not-found" error. Ticket #213 54f1dbc

Not sure I understand why this is back, we now have the same code in two places. I moved this exact code block to the top of the file and used it to set the "url port" setting (which can then be used elsewhere).

Putting it back here doesn't make sense to me.


Ah got you that makes sense, so there's actually two "ports" that should be treated separately, the actual port the application is served on and the port that is used as part of the generated urls.

While we want to take the app port from the url if there is no env variable we don't want to set the url port. I'll fix this up so we only have the logic once.

remy and others added some commits
@remy remy Merge branch 'feature/node' of into feature/node 4d79eae
@remy remy Live now moved to "/watch" fc73f15
@remy remy I need to fix this, but for now, login.js uses the *lack* of message …
…to refresh the page.
@remy remy Update last_updated col on owners so that /rem/last always points to …
…last active (includes db change)
@remy remy Closure for another day 5f598e2
@remy remy Fixed the damn illusive logging out posting to save. Finally fixes #198 bb6cdf0
@remy remy Only hide open menus if the down event didn't originate from inside a…
… popup. Fixes #211
@remy remy IE fixes *and including an IE specific CSS link) 5e3a23b
@remy remy z-index fixes (removed for IE). Fixes #181 61beb09
@remy remy Don't bash "const" sessionStorage. Bit nasty, but does the trick. 0d7f3a1
@remy remy Bigger hit target - the 1px felt to small for me. Maybe it's just me …
@remy remy Fixed #216. This was checking if request accepted event-stream, brows…
…er was sending accepts "*/*" - therefore it did. LOL.
@remy remy Removed logging 0ca398c
@remy remy Pushing the latest welcome screen a08dfd6
@remy remy Update welcome a66818f
@remy remy send the JavaScript content since we need it for codecasting 85697e7
@bundyo bundyo Add Kendo UI libraries. d8520b3
@bundyo bundyo Add quotes. d3e04e7
@remy remy Merge pull request #219 from bundyo/feature/node
Add Kendo UI to the library templates
@remy remy Remove class from inserted libraries - not needed for new technique dfdff17
@remy remy Allow settings to disable jshint 6005497
@remy remy Expose the public API for setting custom settings 077214d
@remy remy Fixed loading of the sync-worker ceebfc5
@remy remy Removing username from title 7463ef4
@remy remy Moved title update to prepare code e39129b
@remy remy Expose some key settings to the user's api bd3d580
@remy remy Moved back to cmd+n for panels. 9803e31
@remy remy Now correctly reading content from HTML and offering CSS as content. …
…Fixes #162
@remy remy Making input boxes slightly wider (for share box) 533257e
@remy remy MOAR TODO!!!! 1f12b6b
@remy remy When focusing an input, let's highlight it 97eb69f
@remy remy Removed title update stuff - should happen on render 0db66e6
@remy remy Open shortcut e68adbd
@remy remy Fixed exception in objectValue lookup function 7f1f05c
@remy remy Exposing more methods to share URL - needs a little more work bbac264
@remy remy Always show the rendered output on open 33a192e
@remy remy Remove query from url upon restore from url 9c8c20a
@remy remy Saving now updates the share urls 75444ef
@remy remy Fixed #215. Change avatar when email is changed. 763c076
@remy remy Put alt back in to showing panels c9203cc
@remy remy Dave! 55a08fa
@remy remy Show and hide the pop out preview link dab5413
@remy remy Whoops - new urls redirected to /edit which caused breakage. 2028bf4
@aron aron Set NODE_ENV from the config file unless already defined 55a9044
@aron aron Move the hogan renderer into a separate file 74c7ed3
@aron aron Move routes into a separate file to keep things tidy f4f122a
@remy remy Docs dd82f01
@remy remy Markdown supported and better processor support 03649ac
@aron aron Add a 500 page and an ErrorHandler object
This should display a friendlier error page when in production based on
the lovely JSBin welcome page.
@aron aron Display an HTTPError better as plain text 4105921
@aron aron Move all configuration into a app.configure() block 31fda88
@aron aron Implement the error handlers in the routes.js file e384ae7
@aron aron Add ability to send an error report when JSBin crashes b66c5ca
@aron aron Now sending a simple error report when JSBin crashes #213
This can be enabled by adding a "notify" key to your config file:

  "notify": {
    "errors": ["John Doe <>"]

This can contain one or more email addresses. They will be sent an email with
the url, stack trace and other request information.
@aron aron Tidy up the port code
We now detect the port from the POST environment variable. If this fails
we extract it from the setting. This then available via
app.set("port") for use in your own modules.
@aron aron Update the bin/jsbin file to use the new "port" setting 5c60937
@aron aron Improved use of url.prefix setting
Now instead of mounting jsbin inside another express() instance we
simply mount the router and static files under the prefix.
@aron aron Add reserved words to default config. Ticket #191 7e469db
@aron aron Include express inside routes.js eede79c
@aron aron Allow users to create custom urls. Closes #191
This also checks against the blacklist in the config file for reserved
urls and returns an error if not allowed.
@aron aron Force Accept header in all save requests
This ensures that we get JSON rather than HTML back in the response.
@aron aron Now show preview of not found bin if no edit in url bf03201
@aron aron Added a fallback 404 page 72b7cd5
@remy remy BOOM. Closes #176
Now just need @aron to implement server side rendering so the previews
work now (that I've broken them with this support! :)
@remy remy .trim() polyfill and adding comment rendered JS c711042
@remy remy Merge branch 'feature/node' of into feature/node 40c3522
@remy remy Fixed the exposed API 53941f6
@alejandro alejandro [fix] Missing ">" bfab3cf
@remy remy Merge pull request #222 from alejandromg/patch-1
[fix] Missing ">"
@remy remy Adjusted the protected list - moved welcome out in particular 7286226
@remy remy typo 70c94dc
@remy remy Again - typo! d755038
@aron aron Improve handling of mailer when no credentials are provided
Now gracefully handle missing email credentials rather than blowing up.
@aron aron Add new BinHandler#createRevisionOrClone() handler
This re-instates the cloning of bins and fixes #214.
@aron aron Update the default mail config to use sendmail #224 239f67a
@aron aron Mailer now accepts any options supported by nodemailer
Config now uses same format as database in that there is an adapter
Sendmail/SMTP/SES and a matching key of options. Sendmail is used
by default. Closes #224.


    "adapter": "SMTP",
    "SMTP": {
      "service": "Gmail",
      "auth": {
        "user": "",
        "pass": "somelongpassword"

See: for a list of options.
@aron aron More improvements to mailer error handling 6d19eaa
@aron aron Lowercasing email config options 4f45f47
@aron aron Allow email to be disabled by setting "email": null 66f880f
@aron aron Differentiate between email error messages
Now has two types one for email blowing up and one for email being
@aron aron Update bin/jsbin to work with app changes
 * Now using NODE_ENV over ENV as this is supported by express
 * Display the port number when running the app.
@remy remy Fixed undefined on state.processor 6105d63
@remy remy Merge branch 'feature/node' of into feature/node e580c06
@remy remy Borrowing extend form jQuery 3e39ce1
@aron aron Using jQuery's deep extend when building the config
This was causing issues with child keys not being merged correctly.
@aron aron Fixed the deep extend function in the config
It now handles the local config object having keys that are not in the
default config object.
@aron aron Fix an issue with the implementation of clone
This was clobbering the update part of the createRevision() method.
I've got it working and added more comments to hopefully make it
@remy remy Don't every return an empty title dd0dc3c
@remy remy Share menu reveal 1b2744f
@remy remy Removed redundant code, and fixed mousedown->new ca8b169
@remy remy Move unload to jsbin.js to allow api settings to be saved 215c1d3
@remy remy Explicitly call unload when saving external settings bf93e5f
@remy remy Allow settings to be deleted e05472e
@michaelbragg michaelbragg Fix CSS Parsing Errors
Added missing color: to .cm-s-night, .cm-s-night
@remy remy Merge pull request #229 from michaelbragg/feature/node
Fix CSS Parsing Errors
@remy remy Fixed replaceState happening on all url types d5ef375
@remy remy Post continued a86f51d
@remy remy State state all to one position b2381bf
@remy remy Code shuffle 26cc728
@remy remy Stub for API usage 16abb79
@remy remy Support for disabled menu items 1da38f3
@remy remy Merge branch 'feature/node' of into feature/node a396c40
@remy remy cmd+s doesn't save, but it now "ties off" the current revision 7a0801e
@remy remy Disable menu commands rather than hiding them 240f72d
@remy remy Removing redundant style code 800b1ff
@remy remy Tighten code c81a77b
@remy remy -console logging f3163e3
@remy remy Fixed IE rendering shit - basically it would run all the JS in random…
… order crashing the iframe. Lame. So I append a defer it we're working in IE.

Tested and confirmed in IE8 - not yet checked IE9 or 10
@remy remy TODO in IE8 :( 245b637
@remy remy Fixed the IE menu position bug 21f002f
@remy remy Added Angular and Prefixfree to libraries b56169b
@remy remy typo d43a453
@remy remy +lodash 9e04cf4
@remy remy MobileCodeMirror back in place as scroll isn't supported in CodeMirro…
…r on iOS
@remy remy Put embeddedable bins back in Node version 5a9ae0c
@aron aron Set default timezone to UTC. Fixes #232
We need to run node in the same timezone as MySQL uses to store it's
dates so that the node-mysql module coerces the dates correctly. So by
default we assume UTC but this can be configured using the "timezone"
@aron aron Update history preview to parse the dates in the correct timezone
This was previously using the users local timezone which meant
dates could be out. Ticket #232.

An we're in master! Whoop! From now on development should be made in feature/* branches with pull requests to merge into the development branch. master should always contain the latest live version (which we'll also tag).

@aron aron closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.