Archive for June, 2010

Updating ports in FreeBSD 8.0

Ports is the applications repository in FreeBSD. Unlike Ubuntu that provides you with command “apt-get”, in FreeBSD you must manually go to the application folder in “/usr/ports” ( the folder where Ports remain ) and search for the application that you want to install. But what’s the differences between you compile it yourself and using ports. The answer is “dependencies”.

Enough with the introduction, let’s go the main topic. So we are going to update the Ports using cvsup. Yeah… yeah… I know that there are several ways to update the ports, but I prefer to use cvsup ( because it’s the way I taught ). The steps are :
1.Install the cvsup

pkg_add -vr cvsup-without-gui

2.Copy the ports-supfile from example

cp /usr/share/examples/cvsup/ports-supfile .

3.Rehash

rehash

4.Edit the ports-supfile, find the line that say CHANGETHIS.FreeBSD.org. Change it with the mirror that is near you ( I am using BizNet )

5.Run the ports-supfile using cvsup

cvsup -g -L 2 ports-supfile

Wait until the process is complete and your ports will be updated.

Copying files between 2 unix servers

There are many solutions to copy files between 2 unix servers, such as :

  • Copying the files from unix server to your local machine, and then upload the files to the destination server.
  • Using NFS to share the files from your source server to your destination server.
  • Using FTP to copy the files.

First solution is recommended if your files are not much and small in sizes. But if your files are big, then you must provide big storage in your local machine. Using NFS can be an alternate solution, it’s easy to set up, easy to mount the directory and easy to copy the files. But sometimes there are some issues with the NFS, so you must be careful in using NFS.

The last solution is using FTP. Maybe you are wondering “How can I copy between 2 unix servers using FTP ? Do I have to copy it to local machine first ? “. Actually you don’t have to, because there is a technology called ‘XFTP’. They said that you can open 2 Unix Server in different window and copy between that two machines. But I haven’t tested that yet.

Another way is using “self made script” in which I don’t create it myself, I copied it from here. The script allows you to connect to a ftp server, get all the the content of that ftp server and it’s all in terminal ( no GUI, no drag and drop, just bash command ). The script also provides you with several options ( you can get the content of specific folder in the ftp server ).

Here is the complete script in case the website is down :

#! /usr/bin/ksh
 
 
#
#  HardFeed  --  Harvest A Remote Directory via
#                Ftp Enhanced Exhaustive Duplication
#
#  Perderabo  11-23-02
 
VERSION="1.1"    # 03-16-04
 
USAGE="\
HardFeed [ -v | -s | -d | -r | -f | -m | -p password-file 
           -l list-command | -x ftp-command ...  ] system user [directory]
 
use \"HardFeed -h\" use for more documentation
 
-v (verbose)  Print stuff during run
-s (symlink)  Attempt to duplicate any remote symlinks
-d (directory)Attempt to duplicate any remote directories
-r (recurse)  Attempt to descend into any directories and process them
-f (freshen)  If remote file is newer than local file, overwrite the local 
-m (mode)     Attempt a chmod on files and directories that we create
-p (password) Specify a file that contains the password in plaintext
-x (extra)    Specify a command to be sent to the ftp client 
-l (listcmd)  Override the choice of \"ls .\" to get a remote directory"
 
DOCUMENTATION="HardFeed  Version $VERSION
 
$USAGE
 
HardFeed copies all of the contents of a remote directory to the current 
directory using ftp.  It establishes an ftp connection to the remote 
site and it uses the ftp command \"ls\" to get a listing of the remote
directory.  The two required parameters are the remote sytstem and the user
name.  The optional third parameter is the remote directory to copy.  The 
default is just the home directory of the ftp account.
 
HardFeed will prompt you for the password.  This is very secure but it isn't
any good if you want to run HardFeed automatically. You can set the password in
the environment variable HARDFEED_P as an alternate.  HardFeed will set an
internal variable to the password and then clobber the variable HARDFEED_P,
since on some systems, the environment of another process can be displayed.
With most shells, you can also set an environment variable for one command
only, like this: \"HARDFEED_P=xyzzy HardFeed -dR ftpxy joeblow sourcedir\". 
A second alternative is to specify a \"password file\" with the -p option.  
Such a file contains, in plaintext, the password.  HardFeed will read the file
to get the password.  You must decide which option makes more sense in your
environment.
 
Only files are examined.  If we don't have a copy of the remote file, we 
will get it.  HardFeed will never overwrite an existing file system object
with one exception.  If you specify -f and we have both a remote file and a
local file, the timestamps are compared.  If the remote file is newer, a
retrieval attempt will be made.  The local file must be writable for this
to succeed.  For the timestamp compare to work, you and the remote system
must be in the same timezone.  (You can vary your environment to make this
true.)
 
Normally symbolic links are ignored. But with -s, we will attempt to create
a symlink with the same link data.  Even with -s, we will never overwrite
any existing object with a new symbolic link.  You will need to review any
symlinks created and probably correct them.  
 
Normally, directories are ignored.  If you specify -d, HardFeed will attempt
to create the directory locally.  But again, it will never overwrite an
existing object to create a directory.  If you specify -r, HardFeed will 
attempt to recurse into a directory and process all of the files there.  If
you use both -d and -r, it will copy an entire directory hierarchy.  But you
can leave off -d and only pre-create a few directories if you want.
 
HardFeed will attempt a chmod of any file or directory that it creates if you 
specify -m.  It will try to match the mode of the remote object.
 
HardFeed operates by establishing a co-process to the ftp command.  Normally,
the output from the co-process is sent to an un-named file in /tmp and
discarded.  If you want to capture this output, connect a file to fd 3 and
HardFeed will use it for this purpose.  From ksh the syntax is 3>file.  You 
can also do 3>&1 to see it real time during the run if you really want.
 
You can make HardFeed send the ftp co-process some extra commands after the
connection is established with -x.  
 
HardFeed gets a directory listing by sending a \"ls .\" command to the server.
Some servers will list dot files with this while others won't.  You can use the
-l option to change the command if your server needs a different one to do want
you want. -l \"ls -al\" is one example that I got to work with unix.
 
For a microsoft ftp server, I had some luck with:
 -l \"ls -la\" -x \"quote site dirstyle\"
Note that everything is transferred in binary mode.  -x ascii will switch
everything to ascii mode.  HardFeed supports embedded spaces in filenames.  User
names may be long and contain slashes. All of this may make it somewhat usable 
with microsoft ftp servers."
 
 
IFS="" 
 
#
#  If the password is coming in via the environment, save it in
#  a local variable and then clobber the environment variable
 
unset PASSWORD
if [[ -n $HARDFEED_P ]] ; then
	PASSWORD="$HARDFEED-P"
	HARDFEED_P='********'
fi
 
 
#
#  Parse Command Line
#
set -A OPT_CMDS_LIST
OPT_DIRCMD="ls ."
OPT_VERBOSE=0
OPT_SYMLINKS=0
OPT_DIRECTORIES=0
OPT_RECURS=0
OPT_FRESHEN=0
OPT_MODE=0
OPT_PASSWORDFILE=""
OPT_CMDS=0
error=0
while getopts :vsdrfmhp:x:l:  o ; do
	case $o in
	v)	OPT_VERBOSE=1
		;;
        s)      OPT_SYMLINKS=1
		;;
        d)      OPT_DIRECTORIES=1
                ;;
	r)      OPT_RECURS=1
		;;
	f)	OPT_FRESHEN=1
		;;
	m)	OPT_MODE=1
		;;
	h)	echo "$DOCUMENTATION"
		exit 0
		;;
	p)	OPT_PASSWORDFILE=$OPTARG
		if [[ ! -f $OPT_PASSWORDFILE ]] ; then
			echo error $OPT_PASSWORDFILE is not a file
			error=1
		fi
		;;
	x)	OPT_CMDS_LIST[OPT_CMDS]="$OPTARG"
		((OPT_CMDS=OPT_CMDS+1))
		;;
	l)	OPT_DIRCMD="$OPTARG"
		;;
	?)      print error argument $OPTARG is illegal
		error=1
		;;
	esac
done
shift OPTIND-1
if ((error)) ; then
	echo "$USAGE"
	exit 1
fi
if [[ $# -ne 2 && $# -ne 3 ]] ; then
	echo "$USAGE"
	exit 1
fi
SYSTEM=$1
USER=$2
DIRECTORY=$3
[[ -z $DIRECTORY ]] && DIRECTORY=.
 
#
#  Read password file if one is supplied
 
if [[ -n $OPT_PASSWORDFILE ]] ; then
	read PASSWORD < $OPT_PASSWORDFILE
fi
 
 
#
#  Request password if it didn't come in via env or file
 
if [[ -z $PASSWORD ]] ; then
	print -n password -
	stty -echo
	read PASSWORD
	echo
	stty echo
fi
 
#
#  FD 3 will be the transcript of the ftp co-process.  If the user
#  supplied a file for this, we will use that.  Otherwise it will go
#  to a nameless file in /tmp
 
if print -u3 " Transcript of the ftp co-process for HardFeed" 2>/dev/null ; then
	LOGFILE=""
else
	LOGFILE=/tmp/HardFeed.log.$$
	exec 3>$LOGFILE
	rm $LOGFILE
fi
 
#
#  Max time to wait for arrivial of file.  This is a long time.  During
#  an interactive run, the user can use SIGINT if it seems to be taking
#  too long.  This max is intended to assure that a cron job will not
#  hang forever.
 
OPT_MAXWAIT=15
TIMEOUT=/tmp/HardFeed.timeout.$$
 
#
#  Various other initializations
 
LEV=0
date "+%Y %m" | IFS=" " read THISYEAR THISMONTH
((LASTYEAR=THISYEAR-1))
STARTPATH=$(pwd)
set -A DIR_FILE_NAME
set -A DIR_LINE_NUM
 
#
#  Function to convert month to numeric
 
conv_month() {
	typeset -l month
	month=$1
	case $month in
	jan)	nmonth=1  ;;
	feb)	nmonth=2  ;;
	mar)	nmonth=3  ;;
	apr)	nmonth=4  ;;
	may)	nmonth=5  ;;
	jun)	nmonth=6  ;;
	jul)	nmonth=7  ;;
	aug)	nmonth=8  ;;
	sep)	nmonth=9  ;;
	oct)	nmonth=10 ;;
	nov)	nmonth=11 ;;
	dec)	nmonth=12 ;;
	*)	nmonth=0  ;;
	esac
	echo $nmonth
	return $((!nmonth))
}
 
 
#
# Function to determine if a file system object exists
#
# neither -a nor -e is really portable  8(
 
exists() {
	[[ -f $1 || -d $1 || -L $1 || -p $1 || -S $1 || -b $1 || -c $1 ]]
	return $?
	}
 
 
#
# Function to wait for a file to arrive
 
waitfor() {
	wanted=$1
	if ((OPT_MAXWAIT)) ; then
		((GIVEUP=SECONDS+OPT_MAXWAIT))
	else
		GIVEUP="-1"
	fi
 
	while 	[[ ! -f $wanted && $SECONDS -lt $GIVEUP ]] ; do
		sleep 1
	done
	if [[ ! -f $wanted ]] ; then
		echo "FATAL ERROR:" timed out waiting for:  2>&1
		echo "            " "$wanted"               2>&1
		echo 
		print -p bye  2>/dev/null
		exit 2
	fi
	return 0
}
#
#  Function to decode an "ls -l" line.
 
lsdcode() {
 
	typeset -Z2 nmonth day
	typeset -i8 octal
 
	#
	#  get the line, get the first character, split line into words
 
	line="$1"
	char1=${line%%${line#?}}
	IFS=" "
	set -A  things -- $line
	IFS=""
 
	#
	#  We may have a "total" line which needs to be ignored
 
	if [[ ${things[0]} = total ]] ; then
		set -A  lsdc --  skip 000 000000000000 x x
		return 0
	fi
 
	#
	#
	parser=1
	month=${things[5]}
	xmonth=$(conv_month $month)
	if  conv_month $month > /dev/null ; then
		parser=1
	else
		parser=0
	fi
 
	if ((parser)); then
		#
		# Strict Left to Right Parse Routine 
		#
		# Break out the fields that we want.  This technique requires
		# that the user, group, and size fields never run together and
		# so they must have at least one space between them.  But it 
		# allows some limited support of filenames with embedded spaces.
 
		echo "$line" | IFS=" " read permstring junk junk junk junk \
						month day swing rawname
		if [[ $char1 = l ]] ; then
			link=${rawname#*-\> }
			name=${rawname% -\>*}
		else
			name="$rawname"
			link=""
		fi
	else
		#
		# Outside to Inside Parse Routine 
		#
		# Break out the fields that we want.  This technique requires 
		# that no white space exist in the filename.  But the user, 
		# group, and size  fields may sometimes run together without 
		# causing a problem.
 
		echo "WARNING:" badly formatted line in directory listing for:    >&2
		echo "        " "${line}"                                         >&2
		echo "        " attempting outside-to-inside scan                 >&2
		echo                                                              >&2
 
		((pname=${#things[*]}-1))
		if [[ $char1 = l ]] ; then
			link=${things[pname]}
			((pname=pname-2))
		else
			link=
		fi
		permstring=${things[0]}
		name=${things[pname]}
		month=${things[pname-3]}
		day=${things[pname-2]}
		swing=${things[pname-1]}
		if  conv_month $month > /dev/null ; then
			:
		else
			echo "ERROR: " outside-to-inside scan has also failed >&2
			echo "       " giving up on:                          >&2
			echo "       " "$line"                                >&2
			echo                                                  >&2
			set -A  lsdc --  skip 000 000000000000 x x
			return 0
		fi
	fi
 
 
	#
	#  Ignore . and ..
 
	if [[ $name = . || $name = .. ]] ; then
			set -A  lsdc --  skip 000 000000000000 x x
			return 0
	fi
 
	#
	#  decode permissions  (the permission string is first word
 
	set -A perms -- $(print -- ${permstring#?} | sed 's/./& /g')
	extras=0
	[[ ${perms[2]} = S ]] && { ((extras=extras+4000)); perms[2]=- ; }
	[[ ${perms[2]} = s ]] && { ((extras=extras+4000)); perms[2]=x ; }
	[[ ${perms[5]} = S ]] && { ((extras=extras+2000)); perms[5]=- ; }
	[[ ${perms[5]} = s ]] && { ((extras=extras+2000)); perms[5]=x ; }
	[[ ${perms[8]} = T ]] && { ((extras=extras+1000)); perms[8]=- ; }
	[[ ${perms[8]} = t ]] && { ((extras=extras+1000)); perms[8]=x ; }
 
	binary=2#$(print -- ${perms[@]} | sed 's/ //g;s/-/0/g;s/[^0]/1/g')
	((octal=binary))
	result=$(echo $octal)
	result=${result#??}
	((result=result+extras))
 
	#
	# Decode date and time and convert it to yyyymmddhhmm
 
	nmonth=$(conv_month $month)
	if [[ $swing = *:* ]] ; then
		if [[ $nmonth > $THISMONTH ]] ; then
			((year=LASTYEAR))
		else
			((year=THISYEAR))
		time1=${swing%???}
		time2=${swing#???}
		time="${time1}${time2}"
		fi
        else
                year=$swing
		time="0000"
        fi
 
	#
	#  Output the final record
 
	set -A lsdc -- ${char1} ${result} ${year}${nmonth}${day}${time} ${name} ${link}
	return
}
 
 
#
#  Function to process a remote file
#  We will not overwrite and existing file unless we in "freshen" mode.
#  And unless we are in "freshen" mode, it is an error for a file to
#  pre-exist.
 
process_remote_file() {
	VMESS="${VMESS} is a remote file that"
	do_get=0
	if [[ -f $name ]] ; then
		VMESS="${VMESS} already exists"
		if ((OPT_FRESHEN)) ; then
			line2=$(ls -ld "$name")
			lsdcode "$line2" 
			char12=${lsdc[0]}
			mode2=${lsdc[1]}
			datestamp2=${lsdc[2]}
			name2=${lsdc[3]}
			link2=${lsdc[4]}
			if [[ $datestamp > $datestamp2 ]] ; then
				VMESS="${VMESS} but is out-of-date and"
				do_get=1
			else
				VMESS="${VMESS} and is current"
			fi
		else
			VMESS="${VMESS} and cannot be retrieved"
			echo WARNING: no get since $name exists in ${localpath} >&2
		fi
	else
		do_get=1
	fi
	if ((do_get)) ; then
		print -p get \""$name"\"
		waitfor $name
		VMESS="${VMESS} has been retrieved"
		if ((OPT_MODE)) ; then
			chmod $mode "$name"
		fi
	fi
	if (($OPT_VERBOSE)) ; then
		echo "$VMESS"
	fi
	return 0
}
 
 
#  Function to process a remote directory
#  To this function, a remote directory is just an object that
#  may need to be duplicated in the current directory
 
process_remote_directory() {
 
	VMESS="${VMESS} is a remote directory that"
	if ((OPT_DIRECTORIES)) ; then
		if exists $name  ; then
			if [[ ! -d $name ]] ; then
				VMESS="${VMESS} cannot be created due to pre-existing object"
				echo WARNING: no mkdir since $name exists in ${localpath} >&2
			else
				VMESS="${VMESS} already exists"
			fi
		else
			mkdir "$name"
			VMESS="${VMESS} has been created locally"
			if ((OPT_MODE)) ; then
				chmod $mode "$name"
			fi
		fi
	else
		VMESS="${VMESS} has been ignored"
	fi
	if (($OPT_VERBOSE)) ; then
		echo "$VMESS"
	fi
	if ((OPT_RECURS)) ; then
		if [[ -d "$name" ]] ; then
			cd "$name"
			print -p lcd \""$name"\"
			exec 4<&-
			obtain_and_process_remote_ls "$name"
			print -p cd ..
			print -p lcd ..
			cd ..
			exec 4< ${DIR_FILE_NAME[LEV]}
			lineno=0
			while (( lineno != ${DIR_LINE_NUM[LEV]})) ; do
				read -u4 junk
				((lineno=lineno+1))
			done
		fi
	fi
	return 0
}
 
 
#
#  Function to process a remote symlink
#  Note that we deal with th symlink only --  not
#  the object (if any) that the link points to.
 
process_remote_symlink() {
	VMESS="${VMESS} is a remote symlink that"
	if ((OPT_SYMLINKS)) ; then
		if exists "$name" ; then
			if [[ ! -L $name ]] ; then
				VMESS="${VMESS} cannot be created due to pre-existing object"
				echo WARNING: no symlink since $name exists in ${localpath} >&2
			else
				VMESS="${VMESS} already exists"
			fi
		else
			ln -s "$link" "$name"
			VMESS="${VMESS} has been duplicated locally"
		fi
	else
		VMESS="${VMESS} has been ignored"
	fi
	if (($OPT_VERBOSE)) ; then
		echo "$VMESS"
	fi
}
 
 
#
#  If a remote object is not a file, directory, or
#  symlink, we come here.  
 
process_remote_weirdo() {
	VMESS="${VMESS} is a remote unknown object that has been ignored"
	return 0
	}
 
#
#  This function obtains an "ls" listing from the remote ftp system.  Then it 
#  scans the listing line by line to figure out what to do.  It will completely 
#  process the current directory.
 
obtain_and_process_remote_ls() {
 
	typeset rdir tmpfile okfile   ## local scope variables ##
	rdir=$1
 
	#
	#  Set up variables or modify them if we have recursed
 
	((LEV=LEV+1))
	tmpfile=/tmp/HardFeed.tp.$$.${LEV}
	okfile=/tmp/HardFeed.ok.$$.${LEV}
	if ((LEV == 1)) ; then
		localpath=$STARTPATH
		remotepath=$rdir
	else
		localpath=${localpath}/$rdir
		remotepath=${remotepath}/$rdir
 
	fi
 
	#
	#  Get a copy of the remote dir output in a local file
	#  called $tmpfile 
 
	print -p cd \""$rdir"\"
	print -p $OPT_DIRCMD $tmpfile
	print -p $OPT_DIRCMD $okfile
	waitfor $okfile
	DIR_FILE_NAME[LEV]=$tmpfile
	DIR_LINE_NUM[LEV]=0
	exec 4< $tmpfile
 
	#
	#  process each line
	#
 
	while read -u4 line ; do
		((DIR_LINE_NUM[LEV]=${DIR_LINE_NUM[LEV]}+1))
		lsdcode "$line" 
		char1=${lsdc[0]}
		mode=${lsdc[1]}
		datestamp=${lsdc[2]}
		name=${lsdc[3]}
		link=${lsdc[4]}
		VMESS="${remotepath}/${name}"
		case $char1 in
		skip)   ;;
		-)      process_remote_file
			;;
		d)      process_remote_directory
			;;
		l)      process_remote_symlink
			;;
		*)      process_remote_weirdo
			;;
		esac
	done 
 
#
#  We may have recursed...so we must put everything back the way
#  we found it
 
	localpath=${localpath%$rdir}
	localpath=${localpath%/}
	remotepath=${remotepath%$rdir}
	remotepath=${remotepath%/}
	rm $tmpfile
	rm $okfile
	((LEV=LEV-1))
 
	return 0
}
 
 
#
#  Main Program
#
 
 
ftp -inv >&3 2>&1 |&
print -p open $SYSTEM
print -p user $USER $PASSWORD
print -p binary
 
i=0
while ((OPT_CMDS>i)) ; do
	print -p ${OPT_CMDS_LIST[i]}
	((i=i+1))
done
 
obtain_and_process_remote_ls $DIRECTORY
 
print -p bye
wait
exit 0

You just need to copy all the script, save it to a file, upload it to your server and run it. But first you must install the ksh, in ubuntu you can just type :

sudo apt-get install ksh

Example of using it :

./hardfeed <ftp server> <username> <directory>
  • ./hardfeed : the name of the script
  • ftp server : the ip or the domain of the ftp server
  • username : the username of the ftp
  • directory : directory in the ftp server where you want to get the files from

Here the another options which I copied from the website :
HardFeed ftpserver joeblow somedir
This will connect to “ftpserver” and the user “joeblow”. It will cd to “somedir”. It will look at all of the files (and only the files) there. Each remote file that does not exist in the current directory will be copied to the current directory.

HardFeed -ds ftpserver joeblow somedir
This will work as the above example did. Except now we try to create local copies of any symbolic links or directories that we found in “somedir”. Again, though, we will not overwrite any pre-existing object.

HardFeed -rds ftpserver joeblow somedir
Now we will create copies of any remote directories and desend into them. This will copy an entire directory tree. (except that it continues to ignore special files, pipes, etc.)

HardFeed -rs ftpserver joeblow somedir
This is similiar, except we only desend into pre-existing directories. You can use this to copy part of a directory structure. Just pre-create the few directories that you want to copy.

HardFeed -rdsm ftpserver joeblow somedir
This will copy a directory tree, but this time it will try to duplicate the mode (permissions) on each remote object that is duplicated.

HardFeed -rdsf ftpserver joeblow somdir
The -f is “freshen”. Again it copies a directory tree. But if we have a local file and a remote file, the timestamps are compared. The remote file will overwrite the the local file if the remote file was newer.

Setting up NFS di Ubuntu

NFS ( Network File Sharing ) adalah salah satu fitur di linux yang memungkinkan kita untuk men-share folder dan me-mountingnya ke server lain. Jadi misalnya gwa punya server A dengan folder /var/www/uploads dan gwa pengen folder itu bisa diakses dan dari server B.

Jadi solusinya adalah Server A gwa jadikan NFS Server dan Server B menjadi NFS Client. Dalam kasus ini gwa menggunakan Ubuntu ( karena gwa lagi buru-buru ). Untuk menginstall NFS Server cukup ketik :

sudo apt-get install nfs-kernel-server

Setelah itu tinggal setting folder yang mau dishare. Untuk settingannya terletak di folder /etc/exports, jadi sekarang kita edit dengan command :

sudo vim /etc/exports

Kira-kira begini isinya :

# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
 
/var/www/uploads 202.58.181.0/24(rw,no_root_squash,async)

Penjelasannya kira-kira begini :

  • /var/www/uploads = folder di server yang mau dishare
  • 202.58.181.0/24 = ip yang diallow untuk melakukan nfs
  • (rw,no_root_squash,async) = rulenya ( ini rulenya untuk allow semuanya )

Sekarang anda tinggal restart nfsnya dengan command :

sudo /etc/init.d/nfs restart

Trus login ke dalam server yang pengen dimounting NFS nya dan ketik :

mount <ip nfs server>:/var/www/uploads /var/www/temp

Penjelasannya kira-kira begini :

  • mount : ini diisi dengan ip nfs server / domain
  • /var/www/uploads : ini folder yang mau dishare di nfs server
  • /var/www/temp : ini tempat folder yang dimounting di client

Upload file in CakePHP using Media Plugin

There are many solutions to handle file upload in PHP, one of the common solutions is to create a custom action that will check the type of the file, size, validate whether the file name already exists or not, and the last thing is moving the file using move_uploaded_file(). However, it doesn’t end when the files are in your server, after that you still need to write a function to delete the files, manipulate it if needed and so on.

I already tried several ways to handle upload file in CakePHP, from writing a private action in the app_controller and the last I write a component.

I can upload file, delete file, check the file type using my Upload Component, but I realize that there are many things missing in my component.

In searching for inspiration, I found CakePHP do have serveral plugins to handle File Upload and the features are beyond my component.

One of the plugin is Media Plugin by Davidpersson.

Using the plugin is quite easy, but the wiki and the CakeFest slide is not updated with the new configuration ( I am using v1.3alpha ), so you need to jumped in to the core and trying to understand the new configuration.

Basically the plugin consist of several behaviours :

  • Transfer
  • Polymorphic
  • Meta
  • Generator
  • Coupler

But in this post I will just cover the Transfer,Coupler and Meta behaviour because I only understand these behaviours. So lets go to the implementation part, here is my CakePHP and Media Plugin version :

  1. CakePHP 1.3.0
  2. Media Plugin 1.3 alpha

First you must create a table that has a ‘file’ field in it. Remember, the field must be named ‘file’ or the plugin won’t working. Here is the example with my application :

CREATE TABLE IF NOT EXISTS `photos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `file` varchar(255) NOT NULL,
  `dirname` varchar(255) NOT NULL,
  `basename` varchar(255) NOT NULL,
  `checksum` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;

The field that will be used by the plugin are file, dirname, basename, and checksum. But the three last fields is optional, so you can have it in your table or not (if you are using Coupler, and Meta behaviour you MUST add the there fields ). Next, bake the application ( I was using ‘cake bake’ command ).

After that grab the Media Plugin from the github and put it in the plugins folder of your application. Next you will need to include the plugin to your application, open your bootstrap.php / core.php and add this line in it :

require APP . 'plugins/media/config/core.php';

Then create the folder that will be used for storing the files. Go to your application folder in terminal and type this command ( ex: /var/www/sample ) :

cake media init

The command will ask whether you want to create the directories or not, this is the print out of my terminal :

rudy@rudy-laptop:~/www/dummy$ cake media init
---------------------------------------------------------------
Media Shell
---------------------------------------------------------------
Do you want to create missing media directories now?
[n] &gt; y
/dummy/webroot/media/                              [OK  ]
/dummy/webroot/media/static/                       [OK  ]
/dummy/webroot/media/static/aud                    [OK  ]
/dummy/webroot/media/static/css                    [OK  ]
/dummy/webroot/media/static/doc                    [OK  ]
/dummy/webroot/media/static/gen                    [OK  ]
/dummy/webroot/media/static/ico                    [OK  ]
/dummy/webroot/media/static/img                    [OK  ]
/dummy/webroot/media/static/js                     [OK  ]
/dummy/webroot/media/static/txt                    [OK  ]
/dummy/webroot/media/static/vid                    [OK  ]
/dummy/webroot/media/transfer/                     [OK  ]
/dummy/webroot/media/transfer/aud                  [OK  ]
/dummy/webroot/media/transfer/css                  [OK  ]
/dummy/webroot/media/transfer/doc                  [OK  ]
/dummy/webroot/media/transfer/gen                  [OK  ]
/dummy/webroot/media/transfer/ico                  [OK  ]
/dummy/webroot/media/transfer/img                  [OK  ]
/dummy/webroot/media/transfer/js                   [OK  ]
/dummy/webroot/media/transfer/txt                  [OK  ]
/dummy/webroot/media/transfer/vid                  [OK  ]
/dummy/webroot/media/filter/                       [OK  ]
 
/dummy/webroot/media/transfer/.htaccess is not in your webroot.
Remember to set the correct permissions on transfer and filter directory.

Change the permission of the folder so that the webserver can write in it :

chown -R www-data webroot/media

Configure the ‘Photo’ model like this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Photo extends AppModel {
	var $name = 'Photo';
	var $displayField = 'title';
	var $actsAs = array('Media.Transfer','Media.Coupler','Media.Meta');
	var $validate = array(
		'file' => array(
			'mimeType' => array(
			'rule' => array('checkMimeType', false, array ( 'image/jpeg', 'image/png'))
		),
		'size' => array(
			'rule' => array('checkSize' , '5M')
		)
	));
}

As you can see, I added 3 behaviors ( Transfer, Coupler and Meta ). The transfer behavior is used for uploading, moving and validating the file. The coupler is for deleting the file ( it will automatically delete the file if you delete a record associated with it and also will automatically add the value in dirname and basename ), the last thing that it will do is adding the meta description to the table ( checksum ).

Edit the add.ctp and adding the ‘type’ => ‘file’ in the $this->Form->create and the $this->Form->input(‘file’) so the form can handle file upload. In the controller you don’t need to change anything because the behavior automatically handle the validation, the path and moving the file. this is my controller :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
class PhotosController extends AppController {
 
	var $name = 'Photos';
 
	function index() {
		$this->Photo->recursive = 0;
		$this->set('photos', $this->paginate());
	}
 
	function view($id = null) {
		if (!$id) {
			$this->Session->setFlash(sprintf(__('Invalid %s', true), 'photo'));
			$this->redirect(array('action' => 'index'));
		}
		$this->set('photo', $this->Photo->read(null, $id));
	}
 
	function add() {
		if (!empty($this->data)) {
			$this->Photo->create();
			if ($this->Photo->saveAll($this->data)) {
				$this->Session->setFlash(sprintf(__('The %s has been saved', true), 'photo'));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(sprintf(__('The %s could not be saved. Please, try again.', true), 'photo'));
			}
		}
	}
 
	function edit($id = null) {
		if (!$id && empty($this->data)) {
			$this->Session->setFlash(sprintf(__('Invalid %s', true), 'photo'));
			$this->redirect(array('action' => 'index'));
		}
		if (!empty($this->data)) {
			if ($this->Photo->save($this->data)) {
				$this->Session->setFlash(sprintf(__('The %s has been saved', true), 'photo'));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(sprintf(__('The %s could not be saved. Please, try again.', true), 'photo'));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Photo->read(null, $id);
		}
	}
 
	function delete($id = null) {
		if (!$id) {
			$this->Session->setFlash(sprintf(__('Invalid id for %s', true), 'photo'));
			$this->redirect(array('action'=>'index'));
		}
		if ($this->Photo->delete($id)) {
			$this->Session->setFlash(sprintf(__('%s deleted', true), 'Photo'));
			$this->redirect(array('action'=>'index'));
		}
		$this->Session->setFlash(sprintf(__('%s was not deleted', true), 'Photo'));
		$this->redirect(array('action' => 'index'));
	}
}
?>

and this is my add view :

1
2
3
4
5
6
7
<?php echo $this->Form->create('Photo',array('type' => 'file'));?>
	<?php
		echo $this->Form->input('title');
		echo $this->Form->input('file',array('type' => 'file'));
	?>
<?php echo $this->Form->end(__('Submit', true));?>
</div>

Now you are ready to uploading files, deleting files, and validate them in the model ( for validation you can see the wiki in the github for complete validation ). That’s all :D

Maaf karena saya unfollow kamu

Bulan Juni telah tiba dan tak terasa tahun 2010 sudah berjalan 6 bulan ( bener2 ga terasa sama sekali ). Karena berhubung ini bulan baru maka kembalilah ke rutinitas update blog lagi ( 1 bulan sekali ).

Hari ini gwa melakukan sebuah dosa besar yaitu UNFOLLOW seorang temen gwa di twitter, mungkin terdengar sedikit lebay dan beraroma alay. Sebelum gwa melakukan dosa tersebut gwa sempat termenung 10 menit sambil ngeliatin tombol unfollow dan berharap tombol itu berubah jadi tombol Mute without Unfollow. Mungkin memang sebaiknya Twitter menyediakan sebuah fitur dimana kita filter tweet yang kita butuhkan ( sebenarnya gwa udah sempat googling dan cari tentang twitter filter tapi ternyata hanya ada di aplikasi2 desktop dan gwa malas install2 lagi ).

Back to primary reason kenapa gwa sampai memutuskan untuk unfollow. Jadi Awalnya gwa juga ga suka main Twitter. Yang ada di pikiran gwa saat itu adalah : “alah, napaen twitter sih, ga jelas banget. pasti cuma liatin status orang ga jelas, mendingan facebook aja, ada foto,video,dkk”. Tapi ternyata Twitter punya suatu kelebihan tersendiri, dan ternyata itu cocok sekali dengan kebutuhan gwa yaitu gwa bisa dapat informasi-informasi terbaru langsung dari developer-developer luar negeri.

Kalau kata internet sih ada beberapa tipe orang yang nge-Tweet yaitu orang yang pengen eksis, orang yang pengen ngiklan, orang yang pengen jadiin Twitter sebagai news feeds. Dan gwa termasuk orang yang menggunakan Twitter sebagai news feeds. Jadi gwa suka follow developer-developer luar negeri yang suka nge-Tweet apikasi-aplikasi / teknologi baru. Nah mungkin kalau tweet kamu diganti jadi lebih tech-addict mungkin saat ini saya masih jadi follower kamu, contohnya “Lagi makan xxx sambil nyoba MongoDB, wah ternyata MongoDB punya fitur bla2″ atau “Mau ke xxx buat hacking some xxx framework core dengan route object bla2″

Jadi maaf jika kamu tersinggung karena saya unfollow kamu, bukannya saya sombong, saya benci dengan kamu, ga suka gaya kamu, ga suka tweet kamu, ga suka kamu nge-tweet , tapi mungkin ini adalah pilihan terbaik untuk sekarang.

Mungkin kalau kita terlahir kembali dan gwa berakhir bukan seorang yang suka tech, mungkin saya akan jadi follower kamu lagi. Tapi untuk sekarang, mohon maaf yang sebesar-besarnya.