Comparing version 0.1.2 to 0.1.3
@@ -13,7 +13,3 @@ /** | ||
* Examples: | ||
* argsHash = getopt(argv, "x:y::t"); | ||
* argsHash = getopt(argv, {x:1, y:2, t:0}); | ||
* argsHash = getopt(argv, {x:{argc:1, name:'x-position'}, | ||
* y:{argc:2, name:'y-position'}, | ||
* t:{argc:0, name:'test'}}); | ||
* argsHash = getopt(argv, "x:y::h(-help)"); | ||
* | ||
@@ -74,3 +70,8 @@ * Copyright (C) 2014 Andras Radics | ||
var equals, name = opt, value; | ||
if (options[opt] || options[opt] === 0) { | ||
var aliasDepth = 0; | ||
while (options[opt] && options[opt].alias) { | ||
opt = options[opt].alias; | ||
if (++aliasDepth > 1000) throw new Error("getopt alias loop"); | ||
} | ||
if (options[opt] !== undefined) { | ||
var argc = options[opt].argc || options[opt] || 0; | ||
@@ -91,2 +92,3 @@ value = argv.splice(2, argc); | ||
value = opt.slice(equals+1); | ||
opt = opt.slice(0, equals); | ||
} | ||
@@ -93,0 +95,0 @@ else { |
@@ -12,7 +12,6 @@ /** | ||
var _isGmt = false; // computing GMT, do not add tz offset | ||
var _tzInfo = {info: {}, reloadtm: 0}; // cached tzInfo() | ||
var _tzCache = new TzCache(); // cached tzInfo() data and whether typesetting as GMT | ||
function phpdate( format, timestamp ) { | ||
var dt = (typeof timestamp === 'number') ? new Date(timestamp) : timestamp ? timestamp : new Date(); | ||
var dt = _timestampToDt(timestamp); | ||
var i, output = ""; | ||
@@ -30,11 +29,19 @@ | ||
function gmdate( format, timestamp ) { | ||
var currentlyGmt = _isGmt; | ||
_isGmt = true; | ||
var dt = _timestampToDt(timestamp); | ||
var dt = (typeof timestamp === 'number') ? new Date(timestamp) : timestamp ? timestamp : new Date(); | ||
if (!currentlyGmt) dt = new Date(dt.getTime() + _tzInfo.info.offs * 60 * 1000); | ||
// do not alter the provided Date object, use a copy instead | ||
if (typeof timestamp === 'object') dt = new Date(dt.getTime()); | ||
dt.getFullYear = dt.getUTCFullYear; | ||
dt.getMonth = dt.getUTCMonth; | ||
dt.getDay = dt.getUTCDay; | ||
dt.getDate = dt.getUTCDate; | ||
dt.getHours = dt.getUTCHours; | ||
dt.getMinutes = dt.getUTCMinutes; | ||
dt.getSeconds = dt.getUTCSeconds; | ||
var tz = tzInfo(dt); | ||
var currentlyGmt = _tzCache.isGmt(); | ||
_tzCache.forceGmt(true); | ||
var ret = phpdate(format, dt); | ||
_isGmt = currentlyGmt; | ||
_tzCache.forceGmt(currentlyGmt); | ||
@@ -44,2 +51,8 @@ return ret; | ||
function _timestampToDt( timestamp ) { | ||
return (typeof timestamp === 'number') ? new Date(timestamp) : timestamp ? timestamp : new Date(); | ||
} | ||
// `now` is a Date object which will output timezone-corrected values | ||
// (either localtime, no correction, or gmtime, shifted ahead by tz.offs) | ||
var formatters = { | ||
@@ -51,9 +64,10 @@ d: function(now){ return pad2(now.getDate()); }, | ||
h: function(now){ return pad2(hour1to12(now)); }, | ||
N: function(now){ return pad2(iso8601day(now.getDay())); }, // Mon=1 .. Sun=7 | ||
N: function(now){ return iso8601day(now.getDay()); }, // Mon=1 .. Sun=7 | ||
S: function(now){ return dayNumberOrdinalSuffix(now); }, | ||
w: function(now){ return now.getDay(); }, | ||
z: function(now){ return weekdayOffset().year; }, | ||
z: function(now){ return weekdayOffset(now).year; }, | ||
// W: ISO 8601 week number of the year, weeks starting on Monday | ||
W: function(now){ return iso8601week(now); }, | ||
// AR: php pads with a leading zero if 1..9 | ||
W: function(now){ return pad2(iso8601week(now)); }, | ||
@@ -66,27 +80,30 @@ F: function(now){ return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][now.getMonth()]; }, | ||
L: function(now){ return weekdayOffset().leap; }, | ||
L: function(now){ return weekdayOffset(now).leap ? 1 : 0; }, | ||
// o: ISO 8601 year number | ||
o: function(now){ return pad4(iso8601year(now)); }, | ||
Y: function(now){ return pad4(now.getFullYear()); }, | ||
y: function(now){ return pad4(now.getFullYear() % 100); }, | ||
y: function(now){ return pad2(now.getFullYear() % 100); }, | ||
a: function(now){ return now.getHours() < 12 ? "am" : "pm"; }, | ||
A: function(now){ return now.getHours() < 12 ? "AM" : "PM"; }, | ||
B: function(now){ return Math.floor(1000 * (now.getTime() % 86400000) / 86400000); }, | ||
B: function(now){ var tz = tzInfo(now); | ||
// swatch time is GMT +01:00, ie timestamp 1 is 1am, '041' | ||
var tm = now.getTime() + 3600 * 1000; | ||
return pad3(Math.floor(1000 * (tm % 86400000) / 86400000)); }, | ||
g: function(now){ return hour1to12(now); }, | ||
G: function(now){ return now.getHours(); }, | ||
G: function(now){ return (now.getHours()); }, | ||
H: function(now){ return pad2(now.getHours()); }, | ||
i: function(now){ return pad2(now.getMinutes()); }, | ||
s: function(now){ return pad2(now.getSeconds()); }, | ||
u: function(now){ return pad6(now % 1000 * 1000); }, | ||
u: function(now){ return pad6(now.getTime() % 1000 * 1000); }, | ||
e: function(now){ var tz = tzInfo(now); return (_isGmt ? 'GMT' : tz.tzname); }, | ||
I: function(now){ var tz = tzInfo(now); return (_isGmt ? 0 : tz.isDst ? 1 : 0); }, | ||
O: function(now){ var tz = tzInfo(now); return (_isGmt ? '+0000' : tz.sign + pad2(tz.h) + pad2(tz.m)); }, | ||
P: function(now){ var tz = tzInfo(now); return (_isGmt ? '+00:00' : tz.sign + pad2(tz.h) + ":" + pad2(tz.m)); }, | ||
T: function(now){ var tz = tzInfo(now); return (_isGmt ? 'GMT' : tz.tz); }, | ||
Z: function(now){ var tz = tzInfo(now); return (_isGmt ? 0 : -tz.offs * 60); }, | ||
e: function(now){ var tz = tzInfo(now); return tz.tzname; }, | ||
I: function(now){ var tz = tzInfo(now); return tz.isDst; }, | ||
O: function(now){ var tz = tzInfo(now); return (!tz.offs ? '+0000' : tz.sign + pad2(tz.h) + pad2(tz.m)); }, | ||
P: function(now){ var tz = tzInfo(now); return (!tz.offs ? '+00:00' : tz.sign + pad2(tz.h) + ":" + pad2(tz.m)); }, | ||
T: function(now){ var tz = tzInfo(now); return tz.tz; }, | ||
Z: function(now){ var tz = tzInfo(now); return -tz.offs * 60; }, | ||
c: function(now){ var tz = tzInfo(now); return phpdate("Y-m-d\\TH:i:sP", now); }, | ||
r: function(now){ var tz = tzInfo(now); return (_isGmt ? gmdate : phpdate)("D, d M Y H:i:s O", now); }, | ||
c: function(now){ return phpdate("Y-m-d\\TH:i:sP", now); }, | ||
r: function(now){ return phpdate("D, d M Y H:i:s O", now); }, | ||
U: function(now){ return Math.floor(now.getTime() / 1000); }, | ||
@@ -103,10 +120,27 @@ }; | ||
* ISO-8601 week number of year, weeks starting on Monday | ||
* AR: note that Tue, Jan 1st would be week number 53 (of previous year) | ||
* http://en.wikipedia.org/wiki/ISO_week_date | ||
* The first week of a year is the week that contains the first Thursday of the year | ||
*/ | ||
var offs = weekdayOffset(now); | ||
// offs.week is 0..6 day in week offset | ||
// offs.year is 0..356 day in year offset | ||
// offs.week is 0..6 day in week offset (0 = Sun) | ||
// offs.year is 0..356 day in year offset (0 = Jan 1) | ||
// offs.year % 7 is number of 7-day groups since Jan 1st | ||
// offs.year div 7 is the 0..6 day in 7-day offset (0 = same as Jan 1) | ||
// FIXME: writeme | ||
return '??'; | ||
// ISO weeks start with Mon = 0 | ||
var dayOfIsoWeek = offs.week === 0 ? 6 : offs.week - 1; | ||
var dayOfYear = offs.year; | ||
var dayOfSevenday = offs.year % 7; | ||
var dayOfStartOfYear = dayOfIsoWeek - dayOfSevenday; | ||
if (dayOfStartOfYear < 0) dayOfStartOfYear += 7; | ||
var dayOfLastOfYear = (dayOfStartOfYear + offs.ydays - 1) % 7; | ||
// relative days from Jan 1 to first day in this ISO year | ||
var firstDayOfIsoYear = (dayOfStartOfYear < 4) ? dayOfStartOfYear - 7 : 7 - dayOfStartOfYear; | ||
// relative number of days from Jan 1 to last this in this ISO year | ||
var lastDayOfIsoYear = 99999; | ||
if (dayOfYear < firstDayOfIsoYear) return 52 || 53; // FIXME!! | ||
else if (dayOfYear > lastDayOfIsoYear) return 1; | ||
else return (dayOfYear - firstDayOfIsoYear) % 7; // ??? | ||
} | ||
@@ -119,6 +153,12 @@ | ||
* used instead. | ||
* AR: note that Tue, Jan 1st would be last year, new year starts next Monday. | ||
*/ | ||
// FIXME: writeme | ||
return '????'; | ||
var week = iso8601week(now); | ||
if (week > 50 && now.getMonth() === 0) | ||
// week 52 or 53, final week of previous year | ||
return now.getFullYear() - 1; | ||
else if (week === 1 && now.getMonth() !== 0) | ||
// week 1, first week of next year | ||
return now.getFullYear() + 1; | ||
else | ||
return now.getFullYear(); | ||
} | ||
@@ -131,40 +171,86 @@ | ||
function TzCache( ) { | ||
this.capacity = 20; | ||
this.cache = []; | ||
this.timezone = 'local'; | ||
} | ||
TzCache.prototype.forceGmt = function TzCache_forceGmt( yesno ) { | ||
this.timezone = yesno ? 'UTC' : 'local'; | ||
}; | ||
TzCache.prototype.isGmt = function TzCache_isUtc( ) { | ||
return this.timezone === 'UTC'; | ||
}; | ||
TzCache.prototype.index = function TzCache_index( timestamp ) { | ||
// group timezone info into 15-minute buckets | ||
return Math.floor(timestamp / 1000 / 60 / 15); | ||
} | ||
TzCache.prototype.get = function TzCache_get( timestamp ) { | ||
return this.cache[this.index(timestamp)]; | ||
} | ||
TzCache.prototype.set = function TzCache_set( timestamp, info ) { | ||
var ix = this.index(timestamp); | ||
if (this.cache.length >= this.capacity) { | ||
delete this.cache[Math.floor(Math.random() * this.capacity)]; | ||
} | ||
this.cache[ix] = info; | ||
} | ||
// return timezone info about the date | ||
function tzInfo( now ) { | ||
if (_tzCache.isGmt()) { | ||
// if now is evaluated in a GMT context, all the offsets are zero | ||
return { | ||
offs: 0, | ||
h: 0, | ||
m: 0, | ||
isDst: 0, | ||
tz: 'GMT', // 'T' returns php timezone abbrev, is 'GMT' | ||
sign: '+', | ||
tzname: 'UTC', // 'e' returns php timezone name, is 'UTC' | ||
}; | ||
} | ||
// getting the tz info is slow... cache it, reload every 15 min | ||
var tm = now.getTime(); | ||
if (tm >= _tzInfo.reloadtm || tm <= _tzInfo.reloadtm - 15*60*1000) { | ||
// note: slower to parse now.toString() than to derive from getTimezoneOffset() | ||
_tzInfo.reloadtm = now - (now % (15*60*1000)) + 15*60*1000; | ||
var offset = now.getTimezoneOffset(); | ||
var winterOffset = new Date(0).getTimezoneOffset(); // winter 1970 had no DST in effect | ||
// FIXME: this assumes DST in the northern hemisphere; southern might shift in our winter | ||
var isWestOfGmt = (winterOffset > 0); | ||
var isCurrentlyDst = (offset !== winterOffset); | ||
var offsetMinutes = Math.abs(offset) % 60; | ||
var offsetHours = (Math.abs(offset) - offsetMinutes) / 60; | ||
var tzMap = { | ||
'0': ['GMT', 'GMT', 'GMT'], | ||
'240': ['AST', 'ADT', 'Atlantic'], | ||
'300': ['EST', 'EDT', 'US/Eastern'], | ||
'360': ['CST', 'CDT', 'US/Central'], | ||
'420': ['MST', 'MDT', 'US/Mountain'], | ||
'480': ['PST', 'PDT', 'US/Pacific'], | ||
// Juneau | ||
// Hawaii | ||
}; | ||
// FIXME: only detects a few timezone abbreviations, and presumes US | ||
var tzCode = tzMap[winterOffset] ? tzMap[winterOffset][0 + isCurrentlyDst] : '???'; | ||
var tzName = tzMap[winterOffset] ? tzMap[winterOffset][2] : '???'; | ||
_tzInfo.info = { | ||
offs: offset, | ||
h: offsetHours, | ||
m: offsetMinutes, | ||
dst: isCurrentlyDst, | ||
tz: tzCode, | ||
sign: isWestOfGmt ? "-" : "+", | ||
tzname: tzName, | ||
}; | ||
} | ||
return _tzInfo.info; | ||
var tz = _tzCache.get(tm); | ||
if (tz) return tz; | ||
// note: slower to parse now.toString() than to derive from getTimezoneOffset() | ||
var offset = now.getTimezoneOffset(); | ||
var winterOffset = new Date(0).getTimezoneOffset(); // winter 1970 had no DST in effect | ||
// FIXME: this assumes DST in the northern hemisphere; southern might shift in our winter | ||
var isWestOfGmt = (winterOffset > 0); | ||
var isCurrentlyDst = (offset !== winterOffset); | ||
var offsetMinutes = Math.abs(offset) % 60; | ||
var offsetHours = (Math.abs(offset) - offsetMinutes) / 60; | ||
var tzMap = { | ||
'0': ['GMT', 'GMT', 'GMT'], | ||
'240': ['AST', 'ADT', 'Atlantic'], | ||
'300': ['EST', 'EDT', 'US/Eastern'], | ||
'360': ['CST', 'CDT', 'US/Central'], | ||
'420': ['MST', 'MDT', 'US/Mountain'], | ||
'480': ['PST', 'PDT', 'US/Pacific'], | ||
// Juneau | ||
// Hawaii | ||
}; | ||
// FIXME: only detects a few timezone abbreviations, and presumes US | ||
var tzCode = tzMap[winterOffset] ? tzMap[winterOffset][0 + isCurrentlyDst] : now.toString().slice(35, 38); | ||
var tzName = tzMap[winterOffset] ? tzMap[winterOffset][2] : '???'; | ||
var info = { | ||
offs: offset, | ||
h: offsetHours, | ||
m: offsetMinutes, | ||
isDst: isCurrentlyDst ? 1 : 0, | ||
tz: tzCode, | ||
sign: isWestOfGmt ? "-" : "+", | ||
tzname: tzName, | ||
}; | ||
_tzCache.set(tm, info); | ||
return info; | ||
} | ||
@@ -179,3 +265,3 @@ | ||
var days = [31, 28 + isLeap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; | ||
var dy; | ||
var dy = 0; | ||
for (var i=0; i<mo; i++) | ||
@@ -186,7 +272,8 @@ dy += days[i]; | ||
return { | ||
leap: isLeap, | ||
leap: isLeap, // whether this is a leap year | ||
week: now.getDay(), // day of week, 0=Sunday | ||
month: now.getDate() - 1, // day of month, 0=1st | ||
year: dy, // day of year, 0=Jan1 | ||
mdays: days[now.getDate()-1], // days in month | ||
mdays: days[now.getMonth()], // days in month | ||
ydays: 365 + isLeap, // days in year | ||
}; | ||
@@ -203,7 +290,9 @@ } | ||
function pad2( number ) { | ||
return ( | ||
number >= 10 ? number : "0" + number | ||
); | ||
return number >= 10 ? number : "0" + number; | ||
} | ||
function pad3( number ) { | ||
return number >= 100 ? number : "0" + pad2(number); | ||
} | ||
function pad4( number ) { | ||
@@ -210,0 +299,0 @@ return ( |
@@ -21,3 +21,5 @@ /** | ||
prefix = prefix || ""; | ||
return prefix + Math.floor(Math.random() * 0x1000000).toString(16); | ||
var id = prefix + Math.floor(Math.random() * 0x1000000).toString(16); | ||
while (id.length < 6) id = "0" + id; | ||
return id; | ||
} | ||
@@ -30,12 +32,11 @@ | ||
if (typeof prefix === 'function') { callback = prefix; prefix = null; } | ||
else if (typeof directory === 'function') { callback = directory; prefix = directory = null; } | ||
else if (!prefix && typeof directory === 'function') { callback = directory; prefix = directory = null; } | ||
// TODO: allow synchronous use: if called without a callback, | ||
// return fs.openSync(pathname) or expose thrown Error | ||
else throw new Error("callback required"); | ||
} | ||
directory = directory || process.env.TMPDIR || process.env.TEMP || process.env.TMP || "/tmp"; | ||
directory = directory || process.env.TMPDIR || "/tmp"; | ||
prefix = prefix || ""; | ||
// TODO: allow synchronous use: if called without a callback, | ||
// return fs.openSync(pathname) or expose thrown Error | ||
if (!callback) throw new Error("callback required"); | ||
var pathname = directory + "/" + uniqid(prefix); | ||
@@ -42,0 +43,0 @@ fs.open(pathname, "wx+", parseInt("0666", 8), function(err, fd) { |
{ | ||
"name": "arlib", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "Andras' Utility Functions", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
@@ -1,4 +0,5 @@ | ||
# arlib | ||
arlib | ||
===== | ||
### Andras' Library of Handy Utilities | ||
## Andras' Library of Handy Utilities | ||
@@ -11,2 +12,7 @@ This is a placeholder for some of the code I've been working on | ||
### Installation | ||
npm install arlib | ||
npm test arlib | ||
## Contents | ||
@@ -21,3 +27,4 @@ | ||
system. Like php, it also creates the file to prevent the name from | ||
being reused. | ||
being reused. The default directory is process.env.TMPDIR (else /tmp), | ||
and the default prefix is the empty string. | ||
@@ -29,2 +36,11 @@ var tempnam = require('arlib/tempnam'); | ||
Tempnam() generates random filenames and retries on collision. The more files | ||
in the temp directory, the more chance of name collisions. Although up to 16 | ||
million (2^24) files are possible, the retry approach breaks down when close | ||
to the 16m limit (at 14 million it would take an average of 4 retries to find | ||
an unused name, still ok, but at 15 million 11, not ok). Note that 16 million | ||
files in a single directory is unmanageable; `ls` and `echo *` do not work, | ||
and it takes days to just delete them all off an ext3 filesystem with an | ||
opendir/readdir/unlink loop written in C. | ||
### getopt( argv, optspec ) | ||
@@ -53,3 +69,5 @@ | ||
See [mongoid](https://www.npmjs.org/package/mongoid-js) for details. | ||
The mongoid functionality of arlib was made into separate package, arlib | ||
now includes it as a dependency. | ||
See [mongoid-js](https://www.npmjs.org/package/mongoid-js) for details. | ||
@@ -56,0 +74,0 @@ ### phpdate( format, timestamp ) |
@@ -1,2 +0,7 @@ | ||
phpdate = require('../index').phpdate; | ||
var fs = require('fs'); | ||
var tempnam = require('../tempnam.js'); | ||
var child_process = require('child_process'); | ||
var phpdate = require('../phpdate'); | ||
var gmdate = phpdate.gmdate; | ||
var assert = require('assert'); | ||
@@ -10,4 +15,26 @@ module.exports = { | ||
'should pad to 2 places': function(t) { | ||
assert.equal(gmdate('m', 1), '01'); | ||
t.done(); | ||
}, | ||
'should pad to 3 places': function(t) { | ||
assert.equal(gmdate('B', 1), '041'); | ||
assert.equal(phpdate('B', 1), '041'); | ||
t.done(); | ||
}, | ||
'should pad to 4 places': function(t) { | ||
// note that nodejs typesets '123' without a leading zero | ||
assert.equal(phpdate('Y', new Date("1/1/123")), '0123'); | ||
t.done(); | ||
}, | ||
'should pad to 6 places': function(t) { | ||
assert.equal(phpdate('u', 1), '001000'); | ||
t.done(); | ||
}, | ||
'should report on timestamp number': function(t) { | ||
var str = phpdate('Y-m-d', 86400000/2); | ||
var str = gmdate('Y-m-d', 86400000/2); | ||
t.equal('1970-01-01', str); | ||
@@ -17,2 +44,9 @@ t.done(); | ||
'should report on current time': function(t) { | ||
var str = phpdate('Y-m-d'); | ||
t.equal(str.slice(0, 2), '20'); | ||
t.equal(str.length, '2014-01-01'.length); | ||
t.done(); | ||
}, | ||
'should report on timestamp object': function(t) { | ||
@@ -36,3 +70,110 @@ var str = phpdate('Y-m-d', new Date(86400000/2)); | ||
// TODO: lots more tests | ||
'gmdate should handle ST fall back': function(t) { | ||
var gdt = gmdate('Y-m-d H:i:s', 1194147428000); | ||
var pdt = phpdate('Y-m-d H:i:s', 1194147428000); | ||
assert.equal(gdt, '2007-11-04 03:37:08'); | ||
assert.equal(pdt, '2007-11-03 23:37:08'); | ||
t.done(); | ||
}, | ||
'gmdate should handle DST spring forward': function(t) { | ||
var pdt = phpdate('Y-m-d H:i:s', 514953117000); | ||
var gdt = gmdate('Y-m-d H:i:s', 514953117000); | ||
assert.equal(pdt, '1986-04-26 21:31:57'); | ||
assert.equal(gdt, '1986-04-27 02:31:57'); | ||
t.done(); | ||
}, | ||
'gmdate should handle DT fall back overlap': function(t) { | ||
// FIXME: WRITEME | ||
t.done() | ||
}, | ||
'gmdate should handle DST spring foward in black hole': function(t) { | ||
//var dt1 = gmdate('Y-m-d H:i:s', 514969199 * 1000); // 1:59:59am EST, 6:59:59 GMT | ||
//var dt2 = gmdate('Y-m-d H:i:s', 514969200 * 1000); // 3:00:00am EDT, 7:00:00 GMT | ||
t.done(); | ||
}, | ||
'should typeset gmdate for 1295756896': function(t) { | ||
var dt = gmdate('Z e I O P T', 1295756896000); | ||
//assert.equal(dt, ''); | ||
t.done(); | ||
}, | ||
'fuzz test phpdate with 10k random timestamps': function(t) { | ||
fuzztest(t, phpdate, 'date'); | ||
}, | ||
'fuzz test gmdate with 10k random timestamps': function(t) { | ||
fuzztest(t, gmdate, 'gmdate'); | ||
}, | ||
// TODO: specific tests | ||
}; | ||
function fuzztest( t, phpdate, phpPhpdateName ) { | ||
var timestampCount = 10000; | ||
var formats = [ | ||
"a A g G H i s", | ||
"d D j l N S w", | ||
"z", // weekday offset | ||
"F m M n t L Y y", | ||
"B", // swatch time | ||
"u", // microseconds, not possible with a fixed timestamp -- php is buggy! | ||
"e I O P T", | ||
"Z", | ||
"c", | ||
"r U", | ||
// FIXME: W and o broken still | ||
// "W o", | ||
]; | ||
var i, times = []; | ||
// pick random dates between 1986 (500m) and 2017 (1500m) | ||
for (i=0; i<timestampCount; i++) times.push(Math.floor(Math.random() * 1000000000 + 500000000)); | ||
var doneCount = 0; | ||
for (i in formats) { | ||
(function(format, i) { | ||
tempnam("/tmp", "nodeunit-", function(err, tempfile) { | ||
if (err) throw err; | ||
fs.writeFileSync(tempfile, times.join("\n") + "\n"); | ||
try { | ||
var script = | ||
'ini_set("date.timezone", "US/Eastern");' + | ||
'$nlines = 0;' + | ||
'while ($timestamp = fgets(STDIN)) {' + | ||
' $nlines += 1;' + | ||
' echo ' + phpPhpdateName + '("' + format + '\\n", trim($timestamp));' + | ||
'}' + | ||
'file_put_contents("/tmp/ar.out", "AR: nlines = $nlines\n");' + | ||
'//sleep(10);' + | ||
''; | ||
child_process.exec("php -r '" + script + "' < " + tempfile, {maxBuffer: 100 * 1024 * 1024}, function(err, stdout, stderr) { | ||
var results = stdout.split("\n"); | ||
//console.log("AR: results.length", results.length, stderr); | ||
results.pop(); | ||
assert.equal(results.length, times.length); | ||
var j; | ||
for (j=0; j<times.length; j++) { | ||
var php = phpdate(format, times[j]*1000); | ||
if (php !== results[j]) console.log(format, "::", times[j], phpdate("g G Y-m-d H:i:s", times[j]*1000), "\nAR\n", php, "\nphp -r\n", results[j]); | ||
assert.equal(php, results[j]); | ||
//t.equal(phpdate(format, times[j]*1000), results[j]); | ||
} | ||
fs.unlink(tempfile); | ||
doneCount += 1; | ||
if (doneCount === formats.length) t.done(); | ||
}); | ||
} | ||
catch (err) { | ||
t.ok(false, "php not installed, cannot fuzz test"); | ||
doneCount += 1; | ||
if (doneCount === formats.length) t.done(); | ||
} | ||
}); | ||
})(formats[i], i); | ||
} | ||
} |
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
60711
1331
159
9
1