Active River Computer Solutions
Coding Guidelines and Examples
(updated 12/31/2009)
| Website - General | Perl |
| HTML/XHTML, CSS | Database |
| JavaScript | Compression/Backup |
| ASP - PerlScript | Miscellaneous |
| Programming - General |
If you find any programming errors, inconsistencies, or other factual errors on this page, please write to us and let us know about it:
Website - General
- ARCS convention, directory names
- ARCS standard, image resizing
- ARCS convention, image size consistency
- ARCS convention, image manipulation
- ARCS coding standard, use W3C "XHTML 1.0 Strict" doctype
- ARCS coding standard, follow XHTML 1.0 Strict coding standards
- ARCS standard, validate pages
- ARCS standard, maximize use of CSS for styling
- ARCS coding standard, on specific document-related tags
- Example, "read-only" <form> <input> field
- Example, JavaScript code to add "target" attribute to an anchor tag
- Coding "Gotcha!", image map not working in Firefox
- Coding "Gotcha!", CSS, float requires an explicit width
- Coding "Gotcha!", variable scope
- Example, window.onload with multiple functions
- Example, enforcing maximum length of a <textarea> field
- Example, JavaScript object
- Example, JavaScript XMLHttpRequest object (POST method, non-FORM data)
- Example, vertical scrolling content
- Example, get elements by class name
- ARCS coding standard, start of ASP/PerlScript file
- Coding consideration, SSI order of execution
- Coding consideration, SSI order of execution and $Server->Execute() scope issue
- Example, code workaround for PerlScript ASP Exit bug
- Example, code workaround for PerlScript ASP Redirect bug
- Example, removing a $Session variable
- System Requirement (Windows,IIS), ASP write access
- Example, getting all values in the "$Request->Form" collection
- Example, reentrant HTML form
- Coding awareness, lc() and uc() functions with undefined
- Example, ADO DB Connection, error checking and getting last ID on auto-increment field
- Coding awareness, usage of a DLL in PerlScript in ASP
- System Setting (Windows,IIS 6), File Upload Size Limits
- Example, file upload (coming soon)
- Top 25 Most Dangerous Programming Errors
- Loop Control Flow (break, last, continue, next, etc.)
- ARCS coding standard, start of Perl script
- Two Perl script "skeletons"
- ARCS convention, Perl script coding style
- Examples, File test operators, file open modes, and basic file I/O
- Examples, substr() "cheat sheet"
- "Cheat sheet": push(), pop(), unshift(), shift(), splice()
- Coding "Gotcha!", "empty" array element
- Coding "Gotcha!", split() function
- Coding "Gotcha!", "foreach my $x(@arr)" loop
- Example, File read/write, and text file line handling
- Example, Getting the time and formatting it, File modification time
- Example, sorting an array
- Example, rounding up a number
- Example, initialize an array with a predetermined number of elements
- Example, getting names of files in a directory
- Examples, concise way of setting a default value with "||" operator
- Example, regex, capitalizing each word in a string
- Example, regex, formatting and validating phone numbers
- Example, regex, validating email addresses
- Example, regex, find a match unless preceded by something (negative lookbehind)
- Example, usage of the Date::Time module
- Example, generating a single common log file that's relatively small
- Example, using a DLL (Win32::API Module)
- ARCS convention, table names
- ARCS coding standard, foreign keys
- ARCS coding standard, search fields should be indexed
- ARCS coding standard, INSERT statement, specify field names
- ARCS coding standard (data security), use parameterized statements
- Coding consideration, child field of a FOREIGN KEY relationship
- Coding consideration, circular referencing with FOREIGN KEY relationships
- Coding "Gotcha!", JOINs and NULLs
- Example, multiple JOINs on the same table
- Example, putting binary string values into a table
Website - General
1. ARCS convention, directory names. Use the following standard subdirectory naming conventions:
| /bkp | backup files |
| /css | Included CSS files |
| /dat | Any data files a coded page might use |
| /db | Database related files (such as table definition files used to created tables in a MySQL database) |
| /doc | Documentation related files |
| /img | Image source files |
| /inc | Include directory for included general code files |
| /js | JavaScript files |
| /log | log files |
| PDF files | |
| /wrk | Working subdirectory; files used in setting up the website but not used by the website pages - you might have multiple wrk subdirectories, such as /img/wrk or /js/wrk |
In a website structure, make sure the directories are "locked down," as appropriate, in the web server (IIS or Apache) settings.
2. ARCS standard, image resizing. When making image files, you should almost never just rely solely on the "width" and "height" attributes of the <img> tag to resize an image. If you need a smaller version of an image file (such as for a thumbnail), then make a resized version of the image file using your graphics editing program and use that. Using <img> tag attributes to do it has two distinct disadvantages: (1) viewer will probably be seeing a lower quality image than otherwise (you're relying on whatever "fast" resizing algorithm is built into the viewer's browser), and (2) if you're referencing a 400 KB image file, then the server is having to send a 400 KB file through the pipeline (which would be very bad for dial-up viewers), whereas if you've made a thumbnail then the server is only sending, say, a 6 KB file. (P.S.: Don't forget that the image resolution should be set to either 72 or 96 dpi for web page image files.)
3. ARCS convention, image size consistency. If displaying multiple images on a web page in a gallery-like manner, for most contexts you'll want to make sure that all of the pictures of a particular kind of size have exactly the same size. Otherwise it looks bad. Say you have medium pictures and small pictures, but the photographs you've scanned, while relatively close, don't have the same sizes or ratios (ratio of width to height). Once you decide on the exact size you want your mediums and smalls to be, say 180 x 110 and 100 x 64 (pixels), then when you're making your resized image files do whatever combination of the following works best with the particular picture you're doing it to to get all of the pictures to the exact same predetermined size: (1) cropping, and/or (2) nonproportional resizing. But use cropping in preference to nonproportional resizing, because it's preferable to refrain from distorting the image. So if it makes sense with the particular picture you're working on to just crop edges to get the selected ratio, then just do that.
4. ARCS convention, image manipulation. When manipulating photos to make image files for display on web pages, be sure to pay attention to brightness and contrast, and color balance and/or hue and color saturation. If the image is a little blurry, play around with your sharpening filters to see if you can improve it. If you're shrinking the image to a smaller size, wait till after you've resized it to apply sharpening, since the shrinking procedure itself can improve the blurriness.
HTML/XHTML, CSS (also see WDG's Web Authoring FAQ)
1. ARCS coding standard, use W3C "XHTML 1.0 Strict" doctype:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2. ARCS coding standard, follow XHTML 1.0 Strict coding standards. Basic standards to keep in mind:
- All tag names must be lowercase.
- All attribute names (including javascript event names, such as "onclick", must be lowercase.
- All tags must be terminated (either self-terminated or with a corresponding terminating tag).
- All attribute values must be quoted.
- All attributes must have values, including "singleton" attributes such as "selected" (which should be written with its value being its name, e.g., <option selected="selected">).
- CDATA data (such as CSS data inside a <style> tag section, or scripting code inside a <script> tag section) should be properly identified. [see sample template below]
- Don't use the "name" attribute for the following tags: a, applet, form, frame, iframe, img, and map. Use only "id" instead. (The "name" attribute is formally deprecated for these elements.)
XHTML 1.0 Standard is here:
XHTML 1.0 (2nd Edition) Specification
XHTML 1.0 (2nd Edition) Specification
3. ARCS standard, validate pages. Use
as primary validator, and
as secondary validator.
(Note that there are only very rare and specific occasions where it's okay for a page to not completely validate, but they do exist.)
4. ARCS standard, maximize use of CSS for styling. Use
as primary validator, and
as secondary validator.
Use external CSS files where it makes sense to do so (linked into a page with the link tag).
5. ARCS coding standard, on specific document-related tags.
Use full <html> tag:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
Use <meta> tag to explicitly specify charset:
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />
|
If using JavaScript in the HTML, use <meta> tag to explicitly specify script language type:
<meta http-equiv="content-script-type" content="text/javascript" />
|
Here's a sample "minimalist" template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />
<meta name="robots" content="index,follow" />
<meta http-equiv="content-script-type" content="text/javascript" />
<title>Page Title</title>
<link rel="stylesheet" type="text/css" href="/css/main.css" />
<script src="/js/process.js" type="text/javascript"></script>
<style type="text/css">
/*<![CDATA[*/
{CSS code here}
/*]]>*/
</style>
<script type="text/javascript">
//<![CDATA[
{JavaScript code here}
//]]>
</script>
</head>
<body>
{HTML body here}
</body>
</html>
6. Example, "read-only" <form> <input> field. To make a
<form> <input> field "read-only" —In the CSS (where "#ddd" and "#444" will be whatever colors you choose for your application):
input.readonly{background-color:#ddd;color:#444} |
Attributes to use in the
<input> tag:readonly="readonly" tabindex="-1" class="readonly" |
7. Example, JavaScript code to add "target" attribute to an anchor tag. With XHTML 1.0 Strict, the "target" attribute has been removed from the anchor tag. Thus, if you use it your page will not be "XHTML 1.0 Strict" valid. However, you can use the "rel" attribute in the anchor tag, in combination with a little piece of JavaScript, to apply a target attribute after the fact, and in this way the page code remains "XHTML 1.0 Strict" valid.
Example of such an anchor tag:
<a href="http://www.textpad.com/" rel="ext">TextPad</a> |
The JavaScript code (which, of course, can be inline in the page, or an external file linked in):
// give anchors with attribute rel="ext" a target attribute of "w1"
function externalLinks()
{
if (!document.getElementsByTagName)
return;
var a = document.getElementsByTagName("a");
for (var i=0;i<a.length;++i)
{
if (a[i].getAttribute("href") && a[i].getAttribute("rel") == "ext")
a[i].target = "w1";
}
}
window.onload = externalLinks;
8. Coding "Gotcha!", image map not working in Firefox. XHTML 1.0 (Strict) requires that the <map> tag be specified using the "id" attribute, but Firefox does not implement this, so to validate you need to keep the "id" attribute but also use the "name" attribute (give it the same value), then it will work okay in Firefox as well as in IE. Code fragments example:
<map id="gomap" name="gomap">
<area href="http://home.nc.rr.com/tuco/looney/acme/atom.html"
alt="Atom Re-Arranger" shape="rect" coords="392,54,406,62" />
<area href="http://home.nc.rr.com/tuco/looney/acme/detonator.html"
alt="Detonator" shape="circle" coords="488,59,3" />
<area href="http://home.nc.rr.com/tuco/looney/acme/boomerang.html"
alt="Boomerang" shape="poly" coords="150,217,190,257,150,243,110,257" />
</map>
{...}
<img src="/img/banner1a.jpg" alt="Acme Corporation" width="576"
height="72" usemap="#gomap" ismap="ismap" style="border:0" />
|
9. Coding "Gotcha!", CSS, float requires an explicit width. CSS Standard: "A floated box must have an explicit width...." Therefore, you must set the width of a floated item, unless by its nature it already has its own width (such as an image).
JavaScript
1. Coding "Gotcha!", variable scope. A variable declared in a function (i.e., not a global variable) has scope everywhere in that function, regardless of where it is declared. In other words, in other languages a variable would have scope only within the code block in which it is declared (such as in an if block, a while loop, or a for loop), but this is not true for JavaScript.
2. Example, window.onload with multiple functions. Here's an example of how to execute multiple functions at the window.onload event:
// window onload functions management
var wfarr=new Array();
function wfAdd(func){wfarr[wfarr.length]=func;}
function wfExec(){for(var i=0;i<wfarr.length;++i){eval(wfarr[i]);}}
function wfLoad(){window.onload=wfExec;}
wfAdd('func1()');
wfAdd('func2()');
wfAdd('func3()');
wfLoad();
This comes in very handy when you want to have more than one function that needs to be executed immediately after the browser has loaded the whole page. Use wfAdd() with each of such funtions you have.
3. Example, enforcing maximum length of a <textarea> field.
function maxLen(id,max) {
var el = document.getElementById(id);
if (el.value.length > max) { el.value = el.value.substr(0,max); }
}
|
<textarea id="fm1Desc" name="fm1Desc" type="text" cols="60" rows="6"
onkeyup="maxLen('fm1Desc',800)"></textarea> |
4. Example, JavaScript object. Here's a simple sample of making an "object" in JavaScript. Note that while you'll see samples on the internet showing examples of putting an object's method functions inside the constructor function, it's actually better to define the method functions outside of the constructor, because if they're defined inside the contructor then a copy of every method is created for every object that is created, instead of more properly having each object use the same function code, which after all is identical for each object.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />
<meta http-equiv="content-script-type" content="text/javascript" />
<title> JavaScript Object - Simple Sample</title>
<script src="/aqc/admin/js/dd1.js" type="text/javascript"></script>
<style type="text/css">
/*<![CDATA[*/
body{
background:#fff;
color:#000;
margin:0;
font:normal 12px arial,verdana,helvetica,sans-serif
}
#main{margin:10px auto;width:600px}
/*]]>*/
</style>
<script type="text/javascript">
//<![CDATA[
function getArea(){
return(this.radius*this.radius*3.14);
}
function getCircumference(){
return(this.radius*2*3.14);
}
function setRadius(rad){
this.radius=rad;
}
// constructor
function Circle(){
this.radius=0;
this.setRadius=setRadius;
this.diameter=2*this.radius;
this.getArea=getArea;
this.getCircumference=getCircumference;
}
function makeCircle(val){
myCircle.setRadius(val);
document.getElementById('response').innerHTML=myCircle.getArea();
}
var myCircle;
window.onload=function(){
myCircle=new Circle();
}
//]]>
</script>
</head>
<body>
<div id="main">
<div style="margin-top:20px">
Enter radius value:
<input type="text" id="radius" />
</div>
<div style="margin-top:10px">
Click on rectangle below to see circle area:
</div>
<div id="response"
style="margin-top:3px;border:1px solid black;width:100px"
onclick="makeCircle(document.getElementById('radius').value);">
</div>
</div>
</body>
</html>
5. Example, JavaScript XMLHttpRequest object (POST method, non-FORM data). Here is sample code (XHTML fragment only) you can use to implement the XMLHttpRequest object (the HTTP communication object used by a web page to communicate with the server without having to refresh the page). This HTTP communication object is also what is frequently referred to as "AJAX", although the term AJAX really refers more generally to the methods of dynamically altering the context of an HTML page based on communication with the server without refreshing the page, of which the XMLHttpRequest object then is simply one of the basic components of AJAX. Note that this example demonstrates sending data to the server using the POST method. In this example, the data being sent is an abitrary chunk of data, that the server side script reads in as one chunk of data and then parses (see the server side script example following below).
Note that the order of function calls is very important, relative to the open() call. It is critical that the open() call be done first, and that setting up the function reference of onreadystatechange and making the setRequestHeader() calls must occur after open() (even though in the case of onreadystatechange this does not seem right). In the case of onreadystatechange, it would actually work okay in certain browsers, such as FireFox, to set up the function reference of the HTTP communication object instance prior to the open() call, which from a programming perspective would seem to be the proper way to do it, but the object would fail to work in Internet Explorer after being used once. Many code examples on the internet show onreadystatechange being set up prior to the open() call, but such an object instance will fail to work in Internet Explorer after the first time it is used.
<style type="text/css">
/*<![CDATA[*/
#infobox{position:absolute;left:18px;top:78px;
border:1px solid #666;height:90px;width:128px;padding:2px 4px;
background:#feb;font:normal 10px verdana,arial,sans-serif;
text-align:left;overflow:auto}
#btn_update{position:absolute;left:26px;top:174px}
#btn_update button{font:normal 10px 'ms sans serif',sans-serif}
#loadind{position:absolute;left:125px;top:181px}
/*]]>*/
</style>
<script type="text/javascript">
//<![CDATA[
var oHTTP;
function GetXMLHTTPObject(){
oHTTP=null;
try{oHTTP=new XMLHttpRequest();} // Firefox, Opera 8.0+, Safari
catch(err){ // Internet Explorer
try{oHTTP=new ActiveXObject('Msxml2.XMLHTTP');}
catch(err){
try{oHTTP=new ActiveXObject('Microsoft.XMLHTTP');}
catch(err){return false;}
}
}
return true;
}
function sendData(url,data){
oHTTP.open('POST',url,true); // parm 3 asynchronous flag
// if you do not issue the open() call before setting "onreadystatechange"
// this will cause problems in IE (but not Firefox) if the user
// invokes the XMLHttpRequest object more than once;
// i.e., if you want to re-use the object, for IE you must set
// "onreadystatechange" AFTER the open() call
oHTTP.onreadystatechange= // use this with asynchronous
function(){
if(oHTTP.readyState==4){
document.getElementById('loadind').innerHTML='';
document.body.style.cursor='auto';
if(oHTTP.status!=200){
alert('HTTP problem [status: '+oHTTP.status+' '+oHTTP.statusText+']');
return;
}
document.getElementById('infobox').innerHTML=oHTTP.responseText;
return;
}
}
// all setRequestHeader() calls must be made after the open() function;
// content type "application/x-www-form-urlencoded" is for POST method
oHTTP.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
oHTTP.setRequestHeader('Content-Length',data.length); // for POST
oHTTP.setRequestHeader('Connection','close'); // for POST
document.getElementById('loadind').innerHTML=
'<img src="/img/loading3.gif" alt="" />';
document.body.style.cursor='wait';
try{oHTTP.send(data);} // null for GET, data variable for POST
catch(err){alert('Error: Failure sending data to server!');}
}
function initHTTPRequest(){
document.getElementById('loadind').innerHTML='';
if(GetXMLHTTPObject()){
// set to anticipated content type
if(oHTTP.overrideMimeType){oHTTP.overrideMimeType('text/html');}
}
else{
alert('Your browser does not support AJAX!');
return false;
}
}
//--------------------------------
// window onload functions management
var wfarr=new Array();
function wfAdd(func){wfarr[wfarr.length]=func;}
function wfExec(){for(var i=0;i<wfarr.length;++i){eval(wfarr[i]);}}
function wfLoad(){window.onload=wfExec;}
wfAdd('initHTTPRequest()');
wfLoad();
//--------------------------------
function updateDB(){
var data='';
// generate data to send to the server
// (compiled from a data structure like a mutlidimensional array)
for(var key in hash1){
data+=info[hash1[key]].ddtask
+"\t"+info[hash1[key]].ddset
+"\t"+info[hash1[key]].ddadj+"\n";}
sendData('ax_postdata.asp',data);
}
//]]>
</script>
</head>
<body>
{ . . . }
<div id="infobox"></div>
<div id="btn_update">
<button onclick="updateDB();">Update Tech<br />Information</button>
</div>
<div id="loadind"></div>
On the server is an ASP script to which the data is being sent, or posted (in this case "ax_postdata.asp"), which in this particular example processes the chunk of data that has been sent to it and then uses this to update a database table. Notice that the script does not necessarily need to return any kind of HTML, but can return anything to the initiating page that the page can then handle as appropriate to the context of your application. In this example the server side script is coded to merely return (the $Response->Write) the data that was sent to it (used for debugging feedback information), formatted in some HTML, unless some error is encountered, in which case an error message is returned.
<%@Language="PerlScript"%><%
use strict;
use Win32::ASP qw(:strict);
use warnings;
use lib 'C:/globalincludes';
require('sub_dbconnect');
my $dbh;
db_connect($dbh);
my $flag_okay_db;
if($dbh->State==1){$flag_okay_db=1;}
else{$flag_okay_db=0;}
my $errcd=0;
my $errmsg='';
if(!$flag_okay_db){
$Response->Write("error: lost connection to database");
return(1);
}
my $txt="[0]<br />\n";
my $data=$Request->Form->Item;
$txt.="data=|$data|";
my $pos1=0;
my $count_flds=3;
my @rec=();
my $str_search='';
while(1){
my $pos2=index($data,"\n",$pos1);
if($pos2<0){last;}
my $line=substr($data,$pos1,$pos2-$pos1);
# parse record into fields
# negative parm 3 here prevents stripping of trailing empty fields
my @fld=split(/\t/,$line,-1);
if(scalar(@fld)!=$count_flds){
$dbh->Close();
$Response->Write(
"[16]error: invalid data - field count is not exactly $count_flds");
return(1);
}
push(@rec,[($fld[0],$fld[1],$fld[2])]);
if($pos1>0){$str_search.=',';}
$str_search.=$fld[0];
$pos1=$pos2+1;
}
#--------------------------------
$txt.="<br /><br />\n";
foreach my $i(0..$#rec){
my $qry=qq{UPDATE th_job
SET id_tech='$rec[$i][1]',adjust='$rec[$i][2]'
WHERE id=$rec[$i][0]};
$txt.="$qry<br />\n";
$dbh->Execute($qry);
if($dbh->Errors->{Count}>0){
$errcd=1;
my $tmp=$dbh->Errors(0)->Number.':'.$dbh->Errors(0)->Description;
$dbh->Close();
$Response->Write("[16]error: SQL UPDATE error ($tmp)");
return(1);
}
}
#--------------------------------
$dbh->Close();
$Response->Write($txt);
%>
6. Example, vertical scrolling content. This is a JavaScript function object, accessing DOM object information, that shows an example of how to scroll content vertically in a <div> (works in both FireFox and IE):
function scrollObject(id){
this.domel = document.getElementById(id);
this.speed = 30; // smaller is faster
this.pause = 5000; // bigger is longer
var flagIE = (this.domel.currentStyle) ? true : false;
var x = 0;
if(flagIE) {x = this.domel.offsetHeight;}
else {
x += parseInt(window.getComputedStyle(this.domel,null).getPropertyValue('height'),10);
x += parseInt(window.getComputedStyle(this.domel,null).getPropertyValue('padding-top'),10);
x += parseInt(window.getComputedStyle(this.domel,null).getPropertyValue('padding-bottom'),10);
x += parseInt(window.getComputedStyle(this.domel,null).getPropertyValue('border-top-width'),10);
x += parseInt(window.getComputedStyle(this.domel,null).getPropertyValue('border-bottom-width'),10);
}
this.scrtop = x;
this.scrtopbot = x;
this.scrtoptop = -x;
var obj = this;
this.scrMove = function(){
if (obj.scrtop < obj.scrtoptop) {obj.scrtop = obj.scrtopbot;}
else {--obj.scrtop;}
obj.domel.style.top = obj.scrtop+'px';
var sp;
if (obj.scrtop != 0) {sp = obj.speed;}
else {sp = obj.pause;}
setTimeout(obj.scrMove,sp);
};
this.scrMove();
}
The code has been condensed a bit by using the DOM object "offsetHeight" information for IE, which is not available in FireFox for which you must determine the offset height (total height) by summing the sizes of the individual pieces (the internal height, the vertical padding, and the top and bottom border). (We could also sum the pieces with IE, but the DOM functions are different from the functions shown above for FireFox, which is why it would increase the amount of code.)
In order to access the relevant DOM object correctly, you must instantiate the object in the window.onload event (i.e., after the browser has loaded the page objects), as follows:
function initWin(){
new scrollObject('scroller');
}
window.onload = initWin;
|
Here's an example of page code that the JavaScript would be associated with:
<div style="position:relative;width:200px;margin-top:8px;
border:1px solid #600;padding:3px;overflow:hidden">
<div id="scroller" style="position:relative;top:-30px;
border:1px outset gold;background:#000;color:gold;padding:2px;
font:normal 12px arial,helvetica,sans-serif">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc porta
<b>ultrices lectus</b>. Suspendisse potenti. Nam felis mauris,
consectetuer non, faucibus ullamcorper, cursus at, lorem.
</div>
</div>
|
Obviously, there are many different ways to do the layout, but here is what is essential to the operation of the vertical scroller:
- You must have the outer div and the inner div.
- The inner div must an "id" value that corresponds to the "id" used to make a new scrollObject in the initWin() function.
- The outer div must have "overflow:hidden".
- The inner div must have "position:relative".
- With FireFox the outer div doesn't need "position:relative", but IE has a bug in the implementation of CSS that causes the "overflow:hidden" to fail unless the outer div also has "position:relative", so you need to use that on the outer div as well (and the extra "position:relative" being there won't cause any problems in FireFox).
- You don't strictly need to set the "top" attribute for the inner div (because the JavaScript handles the "top" value), but setting it prevents any appearance of a visual "jump" occurring when the page first loads (the value should be the negative offset height of the inner div; i.e., the same thing calculated in the scrollObject() function).
7. Example, get elements by class name. Here's a very useful piece of JavaScript code to capture in an array all the DOM elements with the same CSS class name (this comes from The Ultimate getElementsByClassName by Robert Nyman, the multiple class names version):
function getElementsByClassName(oElm,strTagName,oClassNames){
var arrElements=(strTagName=="*"&&oElm.all)?oElm.all:oElm.getElementsByTagName(strTagName);
var arrReturnElements=new Array();
var arrRegExpClassNames=new Array();
if(typeof oClassNames=="object")
{for(var i=0;i<oClassNames.length;++i){arrRegExpClassNames.push(new RegExp("(^|\\s)"+oClassNames[i].replace(/\-/g,"\\-")+"(\\s|$)"));}}
else
{arrRegExpClassNames.push(new RegExp("(^|\\s)"+oClassNames.replace(/\-/g,"\\-")+"(\\s|$)"));}
var oElement;
var bMatchesAll;
for(var j=0;j<arrElements.length;++j){
oElement=arrElements[j];
bMatchesAll=true;
for(var k=0;k<arrRegExpClassNames.length;++k){
if(!arrRegExpClassNames[k].test(oElement.className)){
bMatchesAll=false;
break;
}
}
if(bMatchesAll){arrReturnElements.push(oElement);}
}
return(arrReturnElements)
}
var elSections=new Array();
elSections=getElementsByClassName(document.getElementById("sectionB"),"div","infoItem");
"sectionB" represents the DOM element within which you want the function to search, "div" is the tag type the function checks, and "infoItem" represents the class name you want it to capture. If you enter multiple class names, such as like this
elSections=getElementsByClassName(document.getElementById("sectionB"),"div",["type1","type2"]);
then the function will only capture elements that have both class names (but the order doesn't matter).
ASP/PerlScript (see Introduction to PerlScript)
1. ARCS coding standard, start of ASP/PerlScript file. This should be at the beginning of every ASP-Perlscript file:
<%@Language="PerlScript"%><%
use strict;
use Win32::ASP qw(:strict);
use warnings;
%>
2. Coding consideration, SSI order of execution.
- SSI
- scripts in <% %>
This is why you can't use SSI for dynamic includes. (You can use PerlScript's require() function for dynamic includes.)
3. Coding consideration, SSI order of execution and $Server->Execute() scope issue. The executed ASP file does not have access to the calling ASP's SSI includes. If a file is included in the calling page by using #include, the executed .asp will not use it. For example, you may have a subroutine in a file that is included in your calling page, but the executed .asp will not recognize the subroutine name. You would have to include the file in each executed .asp that requires the subroutine.
Note that with ActivePerl 5.8 there is a PerlScript bug that motivates items 4 and 5 here.
4. Example, code workaround for PerlScript ASP Exit bug. To have an ASP exit before processing the rest of the file (based on a particular condition, such as a database connection failure), simply use the following:
return(1); |
5. Example, code workaround for PerlScript ASP Redirect bug. Don't use the standard $Response->Redirect() function. Instead use the following:
use lib 'C:/web/inc';
# redirect subroutine (workaround Perl 5.8 ASP Redirect bug)
require('sub_redirect');
|
The code in this redirect subroutine is as follows:
sub redirect{
if(scalar(@_)<1){return;}
my $pg=$_[0]; # local copy
$Response->{Buffer}=0;
$Response->Clear;
$Response->{Status}='303 See Other';
$Response->AddHeader('Location',$pg);
}
1;
6. Example, removing a $Session variable. For IIS 5 and later you should use:
$Session->Contents->Remove('variable'); |
For prior to IIS 5 you can use the following:
undef($Session->{'variable'}); |
However, be aware that this does not remove the variable from the Session collection, but simply undefines the value that the variable may have. The parameter itself will still exist in the Session collection, but it just won't have any value. This may work okay for your usage, but you must be aware of the difference to make sure your code operates the way you expect.
7. System Requirement (Windows,IIS), ASP write access. If writing some ASP code that needs to write to a file (such as writing to a text file, or changing data in an Access database), you'll need to add write permission to the file (at the system level, not in IIS). On a Windows 2003 system, you could do this through Explorer with these steps:
- Navigate to the file's directory.
- Right-click on the file, to get the context menu.
- Click on Properties.
- Click the Security tab.
- Click the Add button.
- Click the Advanced button.
- Click the Find Now button.
- Select the IUSR_{servername} Name.
- Click the OK button (twice).
- Select the IUSR_{servername} Name (now in the Security list in the Properties dialog window).
- In the Permissions section click the Allow checkbox to the right of Full Control.
- Click the OK button.
Note that if the file does not exist and your page code actually creates the file (say, in case you use a file open in append mode), then the proper permission is set on the file automatically.
8. Example, getting all values in the "$Request->Form" collection. (This can be very useful for debugging purposes.)
my %parm = ();
foreach my $key(Win32::OLE::in($Request->Form)) {
$parm{$key} = $Request->Form($key)->Item;
}
$Response->Write(qq{<table border="1" cellpadding="2" cellspacing="0">\n});
foreach my $key(sort(keys(%parm))) {
$Response->Write(qq{<tr><td>$key</td><td>$parm{$key}</td></tr>\n});
}
$Response->Write(qq{</table>\n});
Another way to do this, also showing other ASP collections:
use Win32::OLE qw(in);
sub rptArray {
if (@_ < 2) { return; }
$Response->Write(qq{<div style="margin-top:10px;font-size:15px"><b><i>$_[0]</i></b></div>\n});
if (keys(%{$_[1]}) > 0) {
$Response->Write(qq{<table border="1" cellpadding="2" cellspacing="0"
style="width:550px;font-size:11px">\n});
foreach my $key(sort(keys(%{$_[1]}))) {
$Response->Write(qq{<tr><td>$key</td><td>$_[1]{$key}</td></tr>\n});
}
$Response->Write(qq{</table>\n});
}
else { $Response->Write(qq{<div style="font-size:13px"><i>[none]</i></div>\n}); }
}
my %parm;
%parm = ();
foreach my $key(in($Request->Form)) {
$parm{$key} = $Request->Form($key)->Item;
}
rptArray('Form',\%parm);
%parm = ();
foreach my $key(in($Request->QueryString)) {
$parm{$key} = $Request->QueryString($key)->Item;
}
rptArray('QueryString',\%parm);
%parm = ();
foreach my $key(in($Session->Contents)) {
#$parm{$key} = $Session->Contents->Item($key);
$parm{$key} = $Session->{$key};
}
rptArray('Session',\%parm);
%parm = ();
foreach my $key(in($Request->Cookies)) {
$parm{$key} = $Request->Cookies($key)->Item;
}
rptArray('Cookies',\%parm);
%parm = ();
foreach my $key(in($Request->ServerVariables)) {
$parm{$key} = $Request->ServerVariables($key)->Item;
}
rptArray('ServerVariables',\%parm);
9. Example, reentrant HTML form. This is a very basic example of a reentrant form (a form whose "action" calls itself), that you can use as a piece of "skeleton code" to start with:
<%@Language="PerlScript"%><%
use strict;
use Win32::ASP qw(:strict);
use warnings;
my $errcd=0;
my $errmsg='';
my %fm=();
my %err=();
$fm{'task'}=$Request->Form('task')->Item;$fm{'task'}||='';
$err{'name'}=0;
$err{'addr1'}=0;
$err{'addr2'}=0;
$err{'city'}=0;
$err{'state'}=0;
$err{'zip'}=0;
if($fm{'task'} eq 'post'){
$fm{'name'}=$Request->Form('fm_name')->Item;$fm{'name'}||='';
$fm{'addr1'}=$Request->Form('fm_addr1')->Item;$fm{'addr1'}||='';
$fm{'addr2'}=$Request->Form('fm_addr2')->Item;$fm{'addr2'}||='';
$fm{'city'}=$Request->Form('fm_city')->Item;$fm{'city'}||='';
$fm{'state'}=$Request->Form('fm_state')->Item;$fm{'state'}||='';
$fm{'zip'}=$Request->Form('fm_zip')->Item;$fm{'zip'}||='';
if($fm{'addr1'} eq ''){$fm{'addr1'}=$fm{'addr2'};$fm{'addr2'}='';} # "float up"
if($fm{'name'} eq ''){
$err{'name'}=1;
$errmsg.='"Name" is blank<br />';
}
if($fm{'addr1'} eq ''){
$err{'addr1'}=1;
$errmsg.='"Address" is blank<br />';
}
if($fm{'city'} eq ''){
$err{'city'}=1;
$errmsg.='"City" is blank<br />';
}
if($fm{'state'} eq ''){
$err{'state'}=1;
$errmsg.='"State" is blank<br />';
}
if($fm{'zip'} eq ''){
$err{'zip'}=1;
$errmsg.='"Zip" is blank<br />';
}
else{
if($fm{'zip'}!~m/^\d{5}$/){
$err{'zip'}=1;
$errmsg.='"Zip" is invalid format<br />';
}
}
if($errmsg ne ''){$errcd=21;}
# pass data to next page in the process thru session variables
if($errcd==0){
$Session->{'fm_name'}=$fm{'name'};
$Session->{'fm_addr1'}=$fm{'addr1'};
$Session->{'fm_addr2'}=$fm{'addr2'};
$Session->{'fm_city'}=$fm{'city'};
$Session->{'fm_state'}=$fm{'state'};
$Session->{'fm_zip'}=$fm{'zip'};
#### redirect to next page in process would go here ####
return(1);
}
}
else{
$fm{'name'}='';
$fm{'addr1'}='';
$fm{'addr2'}='';
$fm{'city'}='';
$fm{'state'}='';
$fm{'zip'}='';
}
%><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />
<meta http-equiv="content-script-type" content="text/javascript" />
<title>ZP4 COM Object Test</title>
<style type="text/css">
/* <![CDATA[ */
table.collapse{border-collapse:collapse;border-spacing:0}
table.collapse td{padding:0}
div.err{width:300px;margin:6px;color:#111;border:1px solid #f82;background-color:#fe9;padding:3px 6px 4px 6px;font:bold 11px verdana,arial,sans-serif}
form{margin:0}
div.frm{margin:6px;border:2px ridge #9ac;padding:3px 6px 4px 6px;font:normal 11px verdana,arial,sans-serif}
div.frm div.hd{font-size:13px;font-weight:bold;margin-bottom:6px}
div.frm input{font:normal 11px verdana,arial,sans-serif;color:#146}
div.frm p{margin:4px 0 0 0}
div.frm input.btn{font:bold 10px 'ms sans serif',sans-serif}
/* ]]> */
</style>
</head>
<body>
<%
if($errcd){$Response->Write(qq{<div class="err">$errmsg</div>\n});}
$Response->Write(qq{<form method="post" action="testzp4.asp">
<table class="collapse"><tr><td><div class="frm">
<input name="task" type="hidden" value="post" />
<div class="hd">Registration Form</div>
<p>Name: <input name="fm_name" type="text" size="25" maxlength="40" value="$fm{'name'}" /></p>
<p>Address: <input name="fm_addr1" type="text" size="25" maxlength="40" value="$fm{'addr1'}" /></p>
<p>Address 2: <input name="fm_addr2" type="text" size="25" maxlength="40" value="$fm{'addr2'}" /></p>
<p>City: <input name="fm_city" type="text" size="25" maxlength="35" value="$fm{'city'}" />
State: <input name="fm_state" type="text" size="2" maxlength="2" value="$fm{'state'}" />
Zip: <input name="fm_zip" type="text" size="5" maxlength="5" value="$fm{'zip'}" /></p>
<p style="float:right;margin-top:6px"><input class="btn" type="submit" value="Submit" /></p>
<div style="clear:both"></div>
</div></td></tr></table>
</form>
});
%></body>
</html>
10. Coding awareness, lc() and uc() functions with undefined. We don't know if this is universal to Perl, but with ActivePerl 5.8.8 on Windows, if you feed an undefined scalar to the lc() or uc() functions, they will return an empty string. This is useful if you do something like this
where you want your variable to be an empty string rather than undefined, for use in conditionals later on in the code.
my $action = lc($Request->Form('action')->Item); |
11. Example, ADO DB Connection, error checking and getting last ID on auto-increment field. This shows how to (a) do error checking after an Execute(), and (b) get the last ID assigned to an auto-increment key after you insert a new record (this is for MySQL):
my $dbh=$Server->CreateObject("ADODB.Connection");
$dbh->Open('DRIVER={MySQL ODBC 3.51 Driver}; SERVER=sql.sample.com; PORT=3306; UID=user123; PWD=abcxyz; DATABASE=inventory');
my $qry=qq{INSERT tr_cust
(status,code_region,address1,address2,city,state,zip,phone)
VALUES('A','IN','3539 N Kenwood Ave',NULL,
'Indianapolis','IN','46208','3179238403',NULL)};
$dbh->Execute($qry);
if($dbh->Errors->{Count}>0){
my $tmp=$dbh->Errors(0)->Number.':'.$dbh->Errors(0)->Description;
$dbh->Close();
$Response->Write("INSERT error ($tmp)");
# e.g., you want to exit out of the ASP file immediately for this error
return(1);
}
$qry=qq{SELECT LAST_INSERT_ID()};
my $rs=$dbh->Execute($qry);
$rs->MoveFirst;
my $lastID=$rs->Fields(0)->Value;
$rs->Close;
$dbh->Close; # if finished using the DB handle
Then you can use the $lastID later on in the code as appropriate to your application.
12. Coding awareness, usage of a DLL in PerlScript in ASP. Any DLL you're using in an ASP context must be a COM object, and it's used after a "$System->CreateObject('{COM object name}');" statement. You cannot use a "regular" DLL through the Win32::API module in ASP.
13. System Setting (Windows,IIS 6), File Upload Size Limits. This is not really an ASP/Perlscript issue, but has to do with an IIS setting called "AspMaxRequestEntityAllowed".
Step 1: Before you can edit the metabase.xml file you must tell IIS to allow you to edit the file. In IIS, right click the name of the server (right below "Internet Information Services" in the left panel), and select Properties in the context menu. Make sure "Enable Direct Metabase Edit" is on (checked). If it's off, turn it on (click the checkbox).
Step 2: Open the IIS "metabase.xml" file in a text editor. (Location: "C:\windows\sytem32\inetserv".) To change the default size limit (that IIS applies to all websites), go to the "IIsWebService" section and change the value of the attribute "AspMaxRequestEntityAllowed". (The IIS installation default value is 204800.) To change the file upload size limit for a particular website, locate the "IIsWebServer" tag that corresponds to the website (you can search on the host header; such as "example.com", or "www.example.com"), then go to the IIsWebVirtualDir tag that follows that. (You can verify that you have the correct website by checking that the ID numbers in the "Location" attribute values of the "IIsWebServer" tag and the "IIsWebVirtualDir" match each other.) Add this attribute line to the "IIsWebVirtualDir", after the "AppRoot" attribute (where {n} is the size limit you want):
AspMaxRequestEntityAllowed="{n}" |
14. Example, file upload (coming soon)
Programming - General
1. Top 25 Most Dangerous Programming Errors. Read the top 25 most dangerous programming errors here:
2. Loop Control Flow (break, last, continue, next, etc.):
continue, break (C, C++, C#, JavaScript, PHP, Java)
next, last (Perl)
Perl: redo
(restart current iteration from beginning of loop)
Perl: continue [block]
(code executed at then end of each iteration, including after next
and last; note: can use next, last, and redo in a continue
block, but using next would cause a major problem)
|
Perl
1. ARCS coding standard, start of Perl script. Always put the following at the beginning of every Perl script:
use strict;
use warnings;
|
2. Two Perl script "skeletons."
#!/perl/bin/perl -w
use strict;
use warnings;
binmode(STDOUT);
binmode(STDERR);
# some
# code
exit(0);
#!/perl/bin/perl -w
use strict;
use warnings;
binmode(STDOUT);
binmode(STDERR);
sub main;
my $rc = main();
exit($rc);
sub main{
# some
# code
return(0);
}
3. ARCS convention, Perl script coding style. Perl is notorious for having so many different ways to do the same thing. But this can also lead to confusion. Here are some guidelines to follow in regard to writing Perl scripts at ARCS. Note that most of these are intended purposely to make the Perl scripts more "C-like".
- Use Perl 5.8.
- Always use parentheses with functions (e.g., print("Hello world.\n"); NOT print "Hello world.\n";).
- Always use "exit(0);" where the script ends. Of course, where you have the program exit prematurely based on a certain condition, make the exit value something other than zero. If you the exit values unique, then any calling program can use the exit code for information about whether or not your Perl program ran successfully or to know why it exited prematurely.
- Don't use "die" (instead, "print" an error message and/or write to a log file, and "exit" in an "if" statement).
- Don't use "unless" (instead, make the conditional work in an "if" statement).
- Avoid the use of "elsif" (just use nested if's and else's).
- Always wrap conditional code that is only a single line in curly braces even though this is not required. Example:
if ($flag == 7) { $value='Texas'; }
4. Examples, File test operators, file open modes, and basic file I/O.
Some basic file test operators (this is a subset):
| Operator | Meaning |
| -e | file exists |
| -z | exists, and has zero size |
| -f | name refers to a regular file |
| -d | name refers to a directory |
| -s | size, in bytes |
| -M | age, in days |
(Note that test operators can be used on file handles as well.)
File open modes:
| Symbol(s) | Mode |
| < | read |
| > | write (create or overwrite) |
| >> | write (create or append) |
| +< | read/write (no create, overwrite) |
| +> | read/write (create or overwrite) |
| +>> | read/write (create or append) |
Note that the seek() function is irrelevant for a file in append mode (">>"). (In other words, when you write to a file opened in append mode, the write will always be to the end of the file, regardless of if you have invoked a seek() or not.) Thus, for a file in append mode, seek() would only be relevant if you had made it readable as well ("+>>").
local *FH;
if (!open(FH,"< $fname"))
{
print(STDERR "error: can't open \"$fname\"\n");
exit(16);
}
|
Read entire file into memory, into an array (a kind of "slurping"):
my @lines = <FH>; |
If you do that, you should probably check the file size ("-s" file test operator) to make sure you're not reading some giant file and eating (or trying to eat) a huge chunk memory.
For one-line-at-a-time processing (uses much less memory), use something like this:
while (my $line = <FH>)
{
{process line data}
}
|
Use "chomp()" to remove line-terminator [ex: chomp($line);].
For an input text file using either LF (Unix style line-terminator) or CRLF (Windows style line-terminator), don't use binmode(); then regardless of it being either LF or CRLF style, chomp() will work the way you want. Then, on a Windows system, to output with only LF-terminated lines, set binmode() just on the output file immediately after the open() of the file and this will make "\n" refer to only an LF in a print() to the file handle. (Of course, this is only when read mode and write mode are on separate files.) Note: This will not work for a Macintosh-style input file (where the line-terminator is a CR only.
5. Examples, substr() "cheat sheet."
my $y = 'Plate tectonics is part of geology';
# from offset to end
my $x = substr($y,20); # 'art of geology'
# from offset for n characters
my $x = substr($y,9,5); # 'tonic'
# from offset to end minus n characters
my $x = substr($y,16,-4); # 'is part of geo'
# from reverse offset to end (last n characters)
my $x = substr($y,-7); # 'geology'
# from reverse offset for n characters
my $x = substr($y,-15,11); # 'part of geo'
# specified region outside of original string
my $x = substr($y,32); # {undefined} (not empty string); returns warning
# lvalue usage, truncation
my $x = $y;
substr($x,15) = ''; # 'Plate tectonics'
# fourth parameter, insertion
my $x = $y;
substr($x,19,0,'a fun '); # 'Plate tectonics is a fun part of geology'
# fourth parameter, replacement
my $x = $y;
substr($x,19,7,'dynamic'); # 'Plate tectonics is dynamic geology'
|
6. "Cheat sheet": push(), pop(), unshift(), shift(), splice().
| Function | Effect |
| push(@arr,$item) | add to end |
| push(@arr,@items) | add to end |
| pop(@arr) | remove from end |
| unshift(@arr,$item) | add to front |
| unshift(@arr,@items) | add to front |
| shift(@arr) | remove from front |
splice() is used to remove items from an array.
splice(@arr,$offset,$length,@list);
splice(@arr,$offset,$length);
splice(@arr,$offset);
splice(@arr); # same as "@arr = ();"
$rv=splice(...); # last item removed (undef if none)
@rv=splice(...); # list of items removed (empty list if none)
|
Negative offset = starting from end of array.
Negative length = everything from offset to end except for this many items at the end.
No length = everything from offset to end.
Negative length = everything from offset to end except for this many items at the end.
No length = everything from offset to end.
7. Coding "Gotcha!", "empty" array element. When using array elements, such as when initializing an array with values or passing parameters to a function, if you leave an element blank this does not leave an empty or undefined element in the array. For example, if you used a subroutine like this
my $rc = func1($p1,,$p3); |
and then in your subroutine expect the middle parameter ($_[1]) to be undefined, this would be wrong, because in fact $p3 has now become $_[1] (and scalar($_) in the subroutine has a value of 2, not 3). Therefore, if you don't want this behavior (if you don't want $p3 shifted down to the second position), you need to explicitly call your function with an undef as the second parameter, like this:
my $rc = func1($p1,undef,$p3); |
8. Coding "Gotcha!", split() function.
The first parameter of the split() function is always interpreted as a regular expression (but not necessarily in the usual way - see the next note), even if you delimit the value with quote marks.
If you split on a space
split(/ /,$str); |
or
split(' ',$str); |
it is actually interpreted as if you used the regular expression "/\s+/".
split() takes an optional third parameter which is a field limiter. It works like this (take $str to be "58|17|42||" for the example results):
| Statement | Result |
| @arr = split(/\|/,$str) | (58,17,42) |
| @arr = split(/\|/,$str,0) | (58,17,42) |
| @arr = split(/\|/,$str,3) | (58,17,'42||') |
| @arr = split(/\|/,$str,7) | (58,17,42,,) |
| @arr = split(/\|/,$str,-1) | (58,17,42,,) |
| @arr = split(/\|/,$str,-99) | (58,17,42,,) |
So note the following:
- The default parameter value is "0".
- Any negative number has the same effect.
- "0" means strip trailing empty fields.
- Unlike what you might think, if the value is less than the number of delimiters in the string, a positive value does not split on the delimiter in what's left and truncate the rest but puts the entire remaining part of the string in the last field.
- If the value is greater than the number of delimiters in the string, it does not add empty fields to the end to come up to the value of the limit parameter. (In other words, it's a limit, not an enforcer.)
- Also note: With a negative value, trailing empty fields result in empty strings in the array, not {undefined}.
See also Perlmeme's "Using the Perl split() function" for more information about additional idiosyncracies of the split() function.
9. Coding "Gotcha!", "foreach my $x(@arr)" loop. The "$x" refers to each actual item of the array (as it loops through), not a copy. If you alter the value of $x at any time, you are altering the value of that item in the array that it refers to at that point.
Also note that it is immoral to delete or insert anything in the array when iterating through it in the foreach() loop, because you will corrupt the foreach() stepping. Same thing applies to deleting or inserting anything to a hash when you are stepping through the keys of a hash with something like "foreach my $key(keys(%hash))". Perl is extremely loose, but immorality like this is even below its level of tolerability.
10. Example, File read/write, and text file line handling. Use this method as a standard way of opening a file:
# setup input file handle
if (!(-e $file_in))
{
print(STDERR "error: file \"$file_in\" does not exist!\n");
exit(16);
}
local *FILE_IN;
if (!open(FILE_IN,"< $file_in"))
{
print(STDERR "error: can't open input file \"$file_in\"\n");
exit(16);
}
Note that you can use the flock() function on Windows platforms to lock the file, and while this function may also work on some other operating systems, including some Unix systems, this function is not portable across all operating systems (which is why the following shows its use wrapped inside a conditional that checks whether the script is being run on a Windows system):
if ($^O eq 'MSWin32')
{
if (!flock(FILE_IN,LOCK_EX)) # lock file, exclusive use
{
print(STDERR "error: can't lock input file \"$opt{i}\" for exclusive use!\n");
exit(16);
}
}
In regard to writing text files, if you want to write lines with line-terminators that are only a single LF character (Unix-style) on a Windows system, then you should set the file handle to binary mode:
binmode(FILE_OUT); # set output file to binary mode |
If you do this, then when you write a line to the output, the "\n" in the print() statement refers to just a single LF character (hex: 0A).
On a Windows system, for reading text files, you don't need to worry about whether the line-terminator is Unix-style (LF only) or Windows-style (CRLF). On a Windows system, if you do not use binmode() on an input file handle, then the chomp() function will remove the line-terminator correctly regardless. Here's a code fragment for line-by-line reading/processing of a text input file:
my $count_lines = 0;
while (my $line = <FILE_IN>)
{
++$count_lines;
chomp($line);
# ...
}
This shows the regular expression (two lines) for removing leading and trailing whitespace:
$line =~ s/^\s+//; # remove leading whitespace
$line =~ s/\s+$//; # remove trailing whitespace
|
11. Example, Getting the time and formatting it, File modification time. This shows how to get the time and format it:
my($ss,$mm,$hh,$dd,$mo,$yy,$wd,$yd,$isdst)=localtime(time);
$yy+=1900;
++$mo;
# display datetime
printf("%02u/%02u/%04u %02u:%02u:%02u\n",$mo,$dd,$yy,$hh,$mm,$ss);
# where "$fpath" is a file reference
# get timestamp of last modification
my($ss,$mm,$hh,$dd,$mo,$yy,$wd,$yd,$isdst)=localtime((stat($fpath))[9]);
$yy+=1900;
++$mo;
# save formatted timestamp in variable
my $mtime=sprintf("%04u%02u%02u%02u%02u%02u",$yy,$mo,$dd,$hh,$mm,$ss);
The following describes the parts of localtime, in order:
- $ss : seconds past the minute
- $mm : minutes past the hour
- $hh : hours past midnight
- $dd : day of the month
- $mo : number of months since start of the year
- $yy : number of years since 1900
- $wd : number of days since start of the week (Sunday)
- $yd : number of days since start of the year
- $isdst : is daylight savings active flag
12. Example, sorting an array.
sort{$a cmp $b}(@array); # alphabetic sort (default)
sort{lc($a) cmp lc($b)}(@array); # case-insensitive alphabetic sort
sort{$a<==>$b}(@array); # numeric sort
|
13. Example, rounding up a number. (Uses the "ternary operator", aka the "conditional operator".)
$n = ($n == int($n) ? $n : int($n + 1))
|
14. Example, initialize an array with a predetermined number of elements. (Uses the "x" operator. Note: The value to repeat must be on the left of the operator, and the number of times to repeat it must be on the right.)
my @array = (undef) x 7; # set up 7 undefined fields
my @array = (0) x 6; # set up 6 fields of value 0
my @array = ('') x 13; # set up 13 fields of empty strings
|
15. Example, getting names of files in a directory.
my $dir = 'G:/procs/autocheck';
if (!-e($dir))
{
print(STDERR "error: directory \"$dir\" doesn't exist\n");
exit(16);
}
if (!-d($dir))
{
print(STDERR "error: \"$dir\" is not a directory\n");
exit(16);
}
local *DIR; # directory handle
if (!opendir(DIR,$dir))
{
print(STDERR "error: can't read directory \"$dir\"\n");
exit(16);
}
# capture all file names in an array
my @fname;
while (my $fname = readdir(DIR))
{
if (-f($fname))
{ push(@fname,$fname); }
}
16. Examples, concise way of setting a default value with "||" operator. If you wanted to set a default value for a variable, you could use the ternary operator, like this:
my $y = (defined($x) ? $x : ''); |
Here's an alternative way, using the "||" operator:
my $y = $x || ''; |
If you're not concerned about changing the first variable, you could just do it directly, like this:
$x ||= ''; |
my $y = $x || 0; or $x ||= 0; is okay too. Using the "||" this way works because the way it operates is to return the left-hand value if it evaluates to true, or return the right-hand value if the left-hand value evaluates to false regardless of what the right-hand value evaluates to.
17. Example, regex, capitalizing each word in a string.
$string =~ s/\b(\w+)\b/ucfirst($1)/ge; |
18. Example, regex, formatting and validating phone numbers. (Assumes you've already trimmed extraneous whitespace.)
$phone =~ s/^\(*(\d{3})(?:\)(?: )?|(?: |-)?)?(\d{3})(?: |-)?(\d{4})$/$1-$2-$3/;
if ($phone !~ m/^\d{3}-\d{3}-\d{4}$/)
{ $errmsg = "Phone number is invalid."; }
|
19. Example, regex, validating email addresses. (Assumes you've already trimmed extraneous whitespace. Based on the guidelines described in "Characters in the local part of a mail address".)
if ($email !~ m/^[A-Za-z0-9_%+-]+(?:\.[A-Za-z0-9_%+-]+)?[A-Za-z0-9_%+-]*@(?:[A-Za-z0-9-]+\.)+(?:[A-Za-z]{2,4}|travel|museum)$/)
{ $errmsg = "Email address is invalid."; }
20. Example, regex, find a match unless preceded by something (negative lookbehind). The following would remove a trailing comment (begun by "#") from a line, but only if the comment indicator character was not immediately preceded by a backslash character:
$line=~s/(?:(?<!\\)#).*$//; # eliminate trailing comments
|
Note that the regex lookbehind as implemented in most regex engines requires that the lookbehind expression be of fixed length. Lookaheads don't have such a restriction but can be any regex expression. Lookbehinds and Lookaheads can be positive as well as negative (i.e., expression preceding or following must be present, rather than must not be present). See the following for detailed discussion about this regex feature: Lookahead and Lookbehind
21. Example, usage of the Date::Time module. Note that calculations should be done only in the UTC timezone (Universal Time), while changing to local timezone only for getting display values.
use DateTime;
my $dt = DateTime->now();
my @sch_dt=();
for(my $i=0; $i<7; ++$i)
{
$dt->set_time_zone('America/New_York');
# default delimiter for mdy() is dash, but made explicit here
push(@sch_dt,$dt->mdy('-'));
$dt->set_time_zone('UTC');
$dt->add(days=>1); # should do calculations only in UTC
}
foreach my $val(@sch_dt)
{ print("$val\n"); }
That would display something like this:
04-06-2007
04-07-2007
04-08-2007
04-09-2007
04-10-2007
04-11-2007
04-12-2007
|
22. Example, generating a single common log file that's relatively small. There are many different ways to generate log files. For example, a log file can be generated at each run of a program, with a counter or timestamp used in the file name itself, and the log files just accumulate in some location, and then you must write some code to expire out (delete) the oldest files based on some criteria. However, in this particular example, which will provide some examples of useful file manipulation code in Perl, we are maintaining a single relatively small log file. The assumed context for this example is that at each program run, only a relatively small number of lines are written to the log, and each line is relatively short (a few dozen characters at most). The relevant code is loaded into subroutines in an external file so you can just require it into your program and write the log with a single call to the subroutine. Note that you would never use this method with anything other than a relatively small log file, because it involves reading the entire log file and writing almost the entire log file every time, when the log file is at the size limit.
Some details: As previously stated, we're assuming a context for which our log file will be, say, a few dozen KB (the maximum size which we're setting in a "rough" way; in this example only 16384 bytes). (Though not as obvious, we're also assuming that each line is relatively short; the code that arbitrarily deletes 12 lines, if triggered, is where the relatively short lines assumption is implied, but the loop as written does break out if the lines array drops to zero lines.) If the file size exceeds the imposed limit, then we read the entire contents of the log into memory (into an array of lines), delete oldest lines (lines at the beginning of the array) till the total bytes falls below the limit, then also delete some additional arbitrary number of oldest lines, then write our new lines to the log at the end of the file. This code also uses "flock()" to lock the file (which isn't universally cross-platform because this works on Windows and some Unix platforms, but not other Unix platform, and in this code we just wrap flock() so it's only invoked on a Windows platform). A timestamp is automatically prepended to every write. Checks are done in the subroutines so that nothing is done if the file handle is not valid (such as if the file is closed and then you try to write to it again). (Note that this also shows how to pass file handles as parameters to subroutines.)
Also note the following, in regard to the open mode and the use of the "seek()" function. Since we're using "+>>" to open the file, when we write to the file the file pointer will always automatically jump to the end so that we'll always be writing to the end of the file. Thus, when using this particular open mode ("+>>") on a file, the "seek()" will only be relevant to positioning the file pointer for reading from the file. Keep this in mind in regard to the code sample below. (If you had, for example, opened the file in "+<" mode, then "seek()" would also have an effect on the position where data would be written to the file.)
This shows an example (complete code) of using the subroutines (and how easy you can perform the log file operations, using the subroutines that follow):
#!/perl/bin/perl -w
use strict;
use warnings;
use lib 'C:/common/inc';
require('arcs_commonlog_proc7K');
local *FILE_LOG;
# this does all setup/truncation of log file
fstart(*FILE_LOG);
# write something to log
fwrite(*FILE_LOG,'We want to record this in the log');
# write something to log and then close the file
fwriteclose(*FILE_LOG,'Even more comments');
exit(0);
This code below (that we've called "arcs_commonlog_proc7K" in the example above) shows the subroutines that actually perform the actions on the log file. The name of the file is hardcoded in this example, but obviously this could be parameterized to "fstart()". But if you're require'ing this into multiple scripts so that they're all writing to a common log file, you might just want this hardcoded. Or not, as you see fit. Maximum file size is hardcoded. Some of the code here is to make sure we're writing linefeed-only text lines (Unix-style) on the Windows platform we use. Pay special attention to how the "seek()" function is used - the times at which it is invoked is important, such as right after opening the file (since we've specified read/append mode which positions the file pointer at the end of the file), and right after reading the file into memory but right before truncate'ing the file (truncate removes everything from the current position of the file pointer). See other comments in the script. The "1;" at the end, of course, is because this is being require'd into another script. (Note the use of binmode() here - not necessary on a Unix system, but on a Windows system this makes our log file use Unix-style line terminators [i.e., LF only].)
Note the following special values used with the seek() function:
SEEK_SET - beginning of file
SEEK_CUR - current file position
SEEK_END - end of file
SEEK_SET - beginning of file
SEEK_CUR - current file position
SEEK_END - end of file
use Fcntl qw(:flock); # import LOCK_* constants
use Fcntl qw(:seek); # import SEEK_* constants
sub fstart(*){
my $fname = 'C:/programs/project562/log/proc7K.log';
my $maxsize_file = 16384;
# "+" in "+>>" adds "read" to do "read/write"
# ">>" in ">>" will create file if it doesn't exist
# (note: ">" would be bad because it would destroy existing data)
local *FH = $_[0];
open(FH,"+>> $fname");
while (defined(fileno(FH)))
{
if ($^O eq 'MSWin32')
{
if (!flock(FH,LOCK_EX)) # lock file, exclusive use
{ close(FH); last; }
}
binmode(FH); # set binary mode on file
my $lenall = -s($fname); # file test operator "-s" gets file size
# if log file exceeds max size, remove oldest lines
if ($lenall > $maxsize_file){
if (!seek(FH,0,SEEK_SET)) # reset file pointer (due to ">>")
{ close(FH); last; }
my @logline = <FH>; # slurp the file into memory
while ($lenall > $maxsize_file)
{
$lenall -= length($logline[0]);
shift(@logline);
}
# intentionally remove more lines
foreach (1..12) # more efficient to use "foreach" with range operator
{
if (!scalar(@logline)) {last;} # safety break
shift(@logline);
}
#------------------------------------------------
if (!seek(FH,0,SEEK_SET)) # reset file pointer
{ close(FH); last; }
if (!truncate(FH,0)) # truncate file
{ close(FH); last; }
#------------------------------------------------
foreach my $line(@logline) # rewrite file with oldest lines removed
{ print(FH $line); }
}
last;
}
}
sub fwrite(*$){
local *FH = $_[0];
if (!defined(fileno(FH)))
{ return; }
my ($ss,$mm,$hh,$dd,$mo,$yy,$wd,$yd,$isdst) = localtime(time);
$yy += 1900;
++$mo;
printf(FH "[%04u%02u%02u%02u%02u%02u]%s\n", $yy,$mo,$dd,$hh,$mm,$ss,$_[1]);
}
sub fwriteclose(*$){
fwrite($_[0],$_[1]);
close(FH);
}
1;
23. Example, using a DLL (Win32::API Module). (See Win32::API - Perl Win32 API Import Facility at CPAN.) Note that the following example is expecting the appropriate DLL file (in this case, "ZP4.dll") to be in a Windows path. If not, then in the first parameter of the Import() function you should specify the DLL file with the full path. The second parameter is the declaration of the function you want to import. It's best to specify the types in all caps, as shown here. In this example, the context is that the ZP4 functions are used to standardize/correct address records. Open a "session", specify layout of input fields, specify layout of output fields, run the ZP4Correct function on the address record(s) you have, then close the session. (Note that this example doesn't show the person name or company name field, or other fields, being carried through, though in a live application you'd need the extra code to carry them on through, though only the address information related fields are sent into and retrieved from the ZP4Correct function.)
Important Note: As of this writing, we believe that ActivePerl from at least v5.8.4 thru v5.8.8 (build 820) has a bug in it pertaining to thread handling that has to do with incorrect allocation/deallocation of memory (as of 1/17/2008 we don't know anything regarding whether the new v5.10 resolves this problem). If it worked correctly, then the $bufStr variable below would properly be initialized just once outside of the record-reading loop. With the bug, this program would operate unpredictably, and our experience is that it simply stops processing after a few records or even crashes the Perl interpreter. Thus, to get it to run the $bufStr initialization was moved inside the record-reading loop. With this change the program will run and will process the records but each pass through the loop causes a new $bufStr to be made that is not the same as the previous one, the previous memory is not released, so as records are processed the script continues to eat more memory. This is bad. The "undef($bufStr);" was added (as shown below), but this had no effect on the problem. Therefore, this script as shown and as run with the ActivePerl version indicated should not be used in a production environment with more than a few dozen thousand records being processed. We do not know how other Perl interpreters would operate in a similar context. The ZP4.dll itself is a Windows DLL. We don't have the time to do an exhaustive exploration/analysis of this problem. If anyone has more information about this particular problem we would sincerely appreciate you telling us about it. (You can contact us at the address provided at the top of this page.)
#! /usr/bin/perl -w
use strict;
use warnings;
use Win32::API;
binmode(STDOUT);
binmode(STDERR);
my $fname = 'C:/prod/proc173/dat/xfrm_in.txt';
my $fnameo = 'C:/prod/proc173/dat/xfrm_out.txt';
#================================================================
if (!Win32::API->Import('ZP4','VOID ZP4StartSession(LONG* sessionptr)'))
{
print(STDERR 'ZP4StartSession: ',$^E,"\n");
exit(16);
}
if (!Win32::API->Import('ZP4','VOID ZP4StopSession(LONG session)'))
{
print(STDERR 'ZP4StopSession: ',$^E,"\n");
exit(16);
}
if (!Win32::API->Import('ZP4','LONG ZP4InputOrder(LONG session,CHAR* fieldlist)'))
{
print(STDERR 'ZP4InputOrder: ',$^E,"\n");
exit(16);
}
if (!Win32::API->Import('ZP4','LONG ZP4OutputOrder(LONG session,CHAR* fieldlist)'))
{
print(STDERR 'ZP4OutputOrder: ',$^E,"\n");
exit(16);
}
if (!Win32::API->Import('ZP4','LONG ZP4Correct(LONG session,CHAR* inputs,CHAR* outputs)'))
{
print(STDERR 'ZP4Correct: ',$^E,"\n");
exit(16);
}
#================================================================
my $rc;
my $bufx = "\0" x 8;
my $lpSession = unpack('L',pack('p',$bufx)); # make a "long*"
ZP4StartSession($lpSession); # get handle
if (!$lpSession)
{
print(STDERR "session start failed\n");
exit(16);
}
my $reqstr="Address\t"
."Address line 2\t"
."City\t"
."State\t"
."ZIP";
$rc = ZP4InputOrder($lpSession,$reqstr);
if (!$rc)
{
ZP4StopSession($lpSession);
print(STDERR "error: ZP4InputOrder() failed\n");
exit(16);
}
$reqstr="Address (final)\t"
."Address line 2 (final)\t"
."City (final)\t"
."City (preferred)\t"
."State (final)\t"
."ZIP (five-digit)\t"
."ZIP (four-digit add-on)\t"
."Certified\t"
."Error code\t"
."Error message\t";
$rc = ZP4OutputOrder($lpSession,$reqstr);
if (!$rc)
{
ZP4StopSession($lpSession);
print(STDERR "error: ZP4OutputOrder() failed\n");
exit(16);
}
#----------------------------------------------------------------
local *FH;
if (!open(FH,"< $fname"))
{
print(STDERR "error: can't open \"$fname\"\n");
exit(16);
}
local *FHO;
if (!open(FHO,"> $fnameo"))
{
print(STDERR "error: can't open \"$fnameo\"\n");
exit(16);
}
binmode(FHO);
#----------------------------------------------------------------
#my $bufStr = ' ' x 1024;
while (my $rec = <FH>)
{
chomp($rec);
my $pos = index($rec,"\t");
++$pos;
$rec = substr($rec,0,$pos)."\t".substr($rec,$pos);
my $bufStr = ' ' x 1024;
$rc = ZP4Correct($lpSession,$rec,$bufStr);
if (!$rc)
{
ZP4StopSession($lpSession);
print(STDERR "error: ZP4Correct() failed\n");
exit(16);
}
print(FHO $bufStr,"\n");
$bufStr = '';
undef($bufStr);
}
print("OUT OF LOOP\n");
close(FH);
close(FHO);
ZP4StopSession($lpSession); # close session
exit(0);
Database
1. ARCS convention, table names. Use the following standard table naming prefix conventions:
| tu_ | Utility table (e.g., status codes, categories, states, area codes) |
| tr_ | Regular table (e.g., users, customers, technicians) |
| th_ | History table (historical transactions related to the business process) |
| tl_ | Log/transactions table (historical transactions related to database activity) |
| tt_ | Temporary (work) table (used to hold intermediate results in the process of using queries and calculations to produce results in stages until getting final results which are stored in some regularly defined table) |
| tw_ | Web interface information table (info needed for the web interface usage that's not directly related to business process logic) |
2. ARCS coding standard, foreign keys. When defining tables, always put a FOREIGN KEY constraint on any table's field that references the parent field of the table it is based on.
3. ARCS coding standard, search fields should be indexed. When defining tables, if there is a field that is not a key (PRIMARY, FOREIGN, or UNIQUE) that will be used frequently, and the table has more than just a few records, be sure to put an INDEX on it to improve efficiency. With a table of significant size, this will improve performance of the search dramatically.
4. ARCS coding standard, INSERT statement, specify field names. When INSERTing records, always specify field names. Thus, you are not implicitly depending on the fields in the table being in any particular order (since this way you can specify the field names, and write the field data, in any order you wish to use). Written this way, the INSERT code will not be "broken" if the table needs to be altered by adding fields. Note that you can also simply omit those fields if you want the inserted record(s) to take on the default values specified for those fields by the table definition (such as an auto-increment for which MySQL automatically generates the key value when you insert a new record). The example code shown here also demonstrates the syntax for INSERTing multiple records.
INSERT th_job(type,status,id_contact,id_location,id_tech,appt)
VALUES
('TB','Z',1,1,NULL,'2007-3-15 17:30'),
('IB','Z',2,2,NULL,'2007-3-15 13:00'),
('TA','Z',3,3,NULL,'2007-3-15 15:30'),
('TA','Z',4,4,NULL,'2007-3-15 11:00'),
('IA','Z',5,5,NULL,'2007-3-15 18:00'),
('TA','Z',6,6,NULL,'2007-3-15 8:00'),
('IB','Z',7,7,NULL,'2007-3-15 10:00'),
('IA','Z',8,8,NULL,'2007-3-15 14:15'),
('TB','Z',9,9,NULL,'2007-3-15 12:00'),
('TA','Z',10,10,NULL,'2007-3-15 9:00'),
('IA','Z',11,11,NULL,'2007-3-15 10:00'),
('TA','Z',12,12,NULL,'2007-3-15 16:00'),
('IA','Z',13,13,NULL,'2007-3-15 13:45');
5. ARCS coding standard (data security), use parameterized statements. Don't try to escape invalid characters. Don't try to do it yourself. Always use parameterized statements.
See:
SQL Injection Prevention Cheat Sheet (OWASP)
SQL Injection Attacks by Example (Steve Friedl)
SQL Injection Walkthrough (Securiteam)
How To: Protect From SQL Injection in ASP.NET (MSDN)
SQL Injection Prevention Cheat Sheet (OWASP)
SQL Injection Attacks by Example (Steve Friedl)
SQL Injection Walkthrough (Securiteam)
How To: Protect From SQL Injection in ASP.NET (MSDN)
6. Coding consideration, child field of a FOREIGN KEY relationship. If you have a child field of a FOREIGN KEY relationship (a field whose value must be one of the values given in a lookup table) that you want to allow to be "not yet defined", then that field should be defined in the table definition as being NULLable. This is because even while enforcement of the FOREIGN KEY relationship does not allow that field to take on any values that are not in the parent table (or MySQL gives you an error if you try to set it to a value that's not in the referenced table), MySQL specifically allows such a child field to be NULL.
7. Coding consideration, circular referencing with FOREIGN KEY relationships. Since MySQL allows for fields with FOREIGN KEY relationships to be NULL (and thus not have a value which would have to exist in the parent table of the relationship), you can make "circular" FOREIGN KEY relationship, such that Table A has a field that references a field in Table B, and at the same time Table B has a field that references a field in Table A. However, note that when creating the table in the database, you cannot create Table A with the FOREIGN KEY relationship to Table B, because Table B won't exist yet; therefore, you must create Table A without the relationship (though you can then create Table B with the relationship to Table A), and then after you create Table B use ALTER TABLE to add that particular FOREIGN KEY relationship to Table A.
8. Coding "Gotcha!", JOINs and NULLs. When doing a query with a JOIN where the FOREIGN KEY value is NULL, using just the keyword JOIN by itself returns no rows for NULL values. If you want a return row (which will have NULL for the value) you must specify that you want a LEFT JOIN. (Known to be this way for MySQL 5; other engines may differ.) So where
SELECT b.username, a.project
FROM th_project a
JOIN tr_user b ON a.id_user=b.id
|
would give you all projects that had a user assigned to them, but not list any projects where the "id_user" is NULL,
SELECT b.username, a.project
FROM th_project a
LEFT JOIN tr_user b ON a.id_user=b.id
|
would give you all projects including those with a NULL "id_user".
9. Example, multiple JOINs on the same table. Say you have one table that has two FOREIGN KEY fields that refer to the same table. For example, say you have a project table that has two fields that both hold an ID value that refers to a table that holds information about all the users, where one field specifies the ID of the user who authorized the project while the second field specifies the ID of the user who is working on the project. Then say you want to do a query that shows the names of these users for the project. Here's an example of how you write such a query:
SELECT a.project, b.name, c.name
FROM th_project a
LEFT JOIN tr_user b ON a.id_user=b.id
LEFT JOIN tr_user c ON a.id_user=c.id
|
In regard to the use of LEFT JOIN in this example, see the discussion about JOINs and NULLs.
10. Example, putting binary string values into a table. Using a GUI editor with the database can make things real convenient - and can also in certain situations make you waste a huge amount of time trying to figure out what's wrong! For example, if you generate a string of characters using any byte value from 0 to 255 (hex: 0 to FF), then use the Windows copy-and-paste facility to put the string into a table's VARBINARY field using the edit functions of Query Browser for MySQL, you will not be putting into the VARBINARY field what you think are seeing being put into it. Some of the values in the string will have been "invisibly" changed by the copy-and-paste process itself. So to put the binary string into the VARBINARY field correctly, do it the SQL way. Here is an example showing this being done for MySQL (if not MySQL, your syntax for specifying hex values may be different):
INSERT tr_user(type,username,pwd,name_first,name_middle,name_last,status)
VALUES('P','smithst58',x'70737de55baed5b7608d4751c7d441376e26bbe28b739e44',
'Steve',NULL,'Smith','A');
|
In this example, the "pwd" field has been defined as VARBINARY(24), and the letter "x" in front of the single-quote delimited string specifies that it is a string of hex values (70-73-7D-E5-5B-AE-...).
Compression/Backup
1. 7-Zip Usage, miscellaneous notes.
7-Zip Home Page
7-Zip Home Page
7z - uses dlls
7za - self-contained executable
"-ms" refers to "solid mode" (on|off)
7zip format, maximum compression level, "solid mode" on:
Format: 7z a {filename}.7z [{path}/]* -t7z -mx9 -ms=on
Example: 7za a bkpfile32a.7z *.pst -t7z -mx9 -ms=on
7zip format, maximum compression level, "solid mode" off:
Format: 7z a {filename}.7z [{path}/]* -t7z -mx9 -ms=off
Example: 7z a DIRX_files.7z DIRX_files/* -t7z -mx9 -ms=off
7zip format, no compression (store), "solid mode" off:
Format: 7z a {filename}.7z [{path}/]* -t7z -mx0 -ms=off
pkzip format (standard deflate method), maximum compression level:
Format: 7za a {filename}.zip [{path}/]* -tzip -mx9
pkzip format (deflate64 method), maximum compression level:
Format: 7za a {filename}.zip [{path}/]* -tzip -mm=deflate64 -mx9
pkzip format (deflate64 method), maximum compression level, with password "xyz3zyx":
Format: 7za a {filename}.zip [{path}/]* -tzip -mm=deflate64 -mx9 -pxyz3zyx
Example of using 7-zip on the command line to compress all files (automatically including all subdirectories and their files, recursively), but excluding one particular subdirectory (named "junk" in the example) and excluding all files of a particular name regardless of what directory they're in ("thumbs.db" in the example). The first command compresses using 7-zip format (maximum compression, solid-mode off), the second compresses using standard pkzip format (not deflate64):
7za a bkp_aqc.7z H:/arcsi.net/aqc/* -x!H:/arcsi.net/aqc/junk/ -xr!H:/arcsi.net/aqc/thumbs.db -t7z -mx9 -ms=off
7za a bkp_aqc.zip H:/arcsi.net/aqc/* -x!H:/arcsi.net/aqc/junk/ -xr!H:/arcsi.net/aqc/thumbs.db -tzip -mx9
(Use -x!*/ to exclude all subdirectories.)
Note that 7-zip's use of both the exclusion parameter (either a command line reference or the references in a file used to store a list of references to exclude) makes an absolute distinction between relative path referencing and absolute path referencing. If the reference to the directories/files to add to the compressed file is an absolute path reference, and the exclusion parameter is a relative path reference, the exclusion parameter will have no effect, and vice versa.
2. RAR Usage, miscellaneous notes.
RAR Home Page
RAR Home Page
rar.exe - command line version
"-f" - freshen files
"-k" - lock archive
"-m<n>" - set compression method (best: -m5)
"-n@<listfile>" - include files using the specified list file
"-r" - recurse subfolders
"-r0" - recurse subfolders for wildcard names only
"-s" - create solid archive
"-s<n>" - create solid groups using file count
"-s-" - disable solid archiving
"-t" - test files after archiving
"-v<n>[k|b|f|m|M|g|G]" - create volumes
k - kilobytes
b - bytes
m - megabytes
M - millions of bytes
g - gigabytes
G - billions of bytes
f - preset floppy size values (360, 720, 1200, 1440 or 2880)
"-x<file>" - exclude specified file
"-x@<listfile>" - exclude files using a specified list file
RAR format, maximum compression level, "solid mode" on, lock archive:
Format: rar a -m5 -s -k {filename} [{path}/]*
Example: rar a -m5 -s -k bkpfile32a *.pst
RAR format, maximum compression level, "solid mode" off, lock archive:
Format: rar a -m5 -s- -k {filename} [{path}/]*
Example: rar a -m5 -s- -k DIRX_files DIRX_files/*
RAR format, no compression (store), "solid mode" off, lock archive:
Format: rar a -m0 -s- -k {filename} [{path}/]*
RAR format, maximum compression level, "solid mode" off, lock archive,
volume split:
Format: rar a -m5 -s- -k -v100m {filename} [{path}/]*
RAR format, maximum compression level, "solid mode" off, lock archive,
set path inside archive to specified path of source file(s):
Format: rar a -m5 -s- -k -ad {filename} [{path}/]*
Example: rar a -m5 -s- -k -ad archive123 DIRX_files/*
(path inside archive will be "DIRX_files")
RAR format, maximum compression level, "solid mode" off, lock archive,
set path inside archive to specified path of source file(s):
Format: rar a -m5 -s- -k -ap{path2} {filename} [{path1}/]*
Example: rar a -m5 -s- -k -apHold0810 archive123 DIRX_files/*
(path inside archive will be "Hold0810")
Note: Do not put a space between -ap and the path name.
Miscellaneous
Download common Unix command line utility programs (ported to Win32).
Put them in a common directory, add that directory to your environment path, then you can use them in a command shell.
Put them in a common directory, add that directory to your environment path, then you can use them in a command shell.
1. grep Usage, miscellaneous notes.
Use grep --help to see all command line options and descriptions. The following example lists (-l) all files that contain a particular word ("pdfsamples" in the example), and also checks (recurses) through all subdirectories (-r). Use -i option for case-insensitive search.)
grep -l -r pdfsamples * |