Categorieën
Geen categorie

Zang verwijderen uit MP3 liedje

Voor de 50e verjaardag van mijn vader hebben we een liedje geschreven op
de melodie van een bestaand liedje. Helaas konden we van dit liedje niet
een karaoke versie vinden. Gelukkig zijn er allerlei programma’s die de
zang uit een liedje kunnen verwijderen.

Voor het verwijderen van de zang heb ik gebruik gemaakt van de
“Vocal Remover” Winamp plugin van Brian Andrews. Zodra je deze plugin activeert kun je procentueel aangeven hoeveel zang er verwijderd moet worden. Voor de beste resultaten zul je hier een beetje mee moeten spelen.

Zodra je plugin heb gedownload en geïnstalleerd kun je de plugin activeren:
“Opties » Voorkeuren…” (sneltoets Ctrl + P) en vervolgens naar
“Plugin-ins » DSP/Effect” en klikken op “AnalogX Vocal Remover [dsp_vr.dll]”.

De plugin werkt helaas niet voor alle liedjes even goed, maar voor een
gratis plugin is het zeker niet verkeerd. Zodra je de plugin goed hebt
afgesteld kun je er voor kiezen het aangepaste liedje op te slaan in een WAV
bestand. Hiervoor ga je naar: “Opties » Voorkeuren…” (sneltoets Ctrl + P)
en vervolgens naar “Plugin-ins » Uitvoer” klikken op “Nullsoft Disk Write v2.14 [out_disk.dll]” en het liedje afspalen.

Categorieën
PHP WordPress

WordPress media bestanden met rare tekens

Onlangs hebben we een nieuwe WordPress website gelanceerd bij Pronamic. De opdrachtgever heeft deze website netjes gevuld op de ontwikkel- en testomgeving van Pronamic. Vervolgens hebben we deze verplaatst naar de productieomgeving. Hierbij liepen we echter tegen een probleem aan. Veel geüploade bestanden hadden in de bestandsnaam rare tekens, zoals copyright (©) tekens. Op de ontwikkel- en testomgeving leverde dit geen problemen op, maar helaas op de productieomgeving wel.

Aangezien het om een flink aantal bestanden ging was het handmatig aanpassen of opnieuw uploaden niet een optie. Ik kon helaas ook geen geschikte WordPress plugin vinden die dit probleem kon verhelpen. Om die reden heb ik zelf maar even een oplossing ontwikkeld. Allereerst heb ik een MySQL query bedacht die alles © tekens vervangt met een gewone c teken.

UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, '©', 'c') WHERE meta_key = '_wp_attached_file';
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, '©', 'c') WHERE meta_key = '_wp_attachment_metadata';
UPDATE wp_posts SET guid = REPLACE(guid, '©', 'c') WHERE post_type = 'attachment';

Vervolgens moesten de bestanden in de WordPress uploads mag ook gewijzigd worden. Hiervoor heb ik eenvoudig PHP script geschreven en uitgevoerd in de uploads map:

<?php

$rdi = new RecursiveDirectoryIterator('./');
$rii = new RecursiveIteratorIterator($rdi);

foreach($rii as $file) {
	$name = $file->getPathname();

	$copyrightPosition = strpos($name, '©');

	if($copyrightPosition !== false) {
		$newName = str_replace('©', 'c', $name);

		$renamed = rename($name, $newName);

		echo $name, ' = ', $newName, ' = ', ($renamed ? 'renamed' : 'failed'), '<br />';
	}
}

Uiteindelijk heb ik voor de zekerheid alle afbeelding en bijbehorende thumbnails opnieuw laten generen met de Regenerate Thumbnails plugin. Mocht je ook ooit een dergelijke probleem hebben dan hoop ik dat je met bovenstaande code fragmenten dit snel kunt oplossen. Eventueel kan Pronamic ook een plugin voor je ontwikkelen die geautomatiseerd je probleem kan verhelpen. Mocht je nog vragen, opmerkingen en/of tips hebben laat dan gerust een reactie achter.

Categorieën
Magento PHP

Magento factuurdatum toevoegen aan PDF

Bij Pronamic krijgen we regelmatig de vraag om de factuurdatum toe te voegen aan de Magento factuur PDF. Volgens de belastingdienst moet de factuurdatum immers verplicht op de factuur staan. Op internet zijn gelukkig genoeg pagina’s te vinden waarop wordt uitgelegd hoe je dit voor elkaar kunt krijgen.

Als je de factuurdatum achter het factuurnummer wilt plaatsen in de PDF kun je daarvoor de volgende code gebruiken.

$page->drawText(Mage::helper('sales')->__('Invoice Date') . ': ' . Mage::helper('core')->formatDate($invoice->getCreatedAt(), 'full', false), 285, 780, 'UTF-8');

Deze regel kun je toevoegen aan het bestand ‘app/code/local/Mage/Sales/Model/Order/Pdf’ onder de regel:

$page->drawText(Mage::helper('sales')->__('Invoice # ') . $invoice->getIncrementId(), 35, 780, 'UTF-8');

De datum kan in verschillende formaten worden weergegeven in de PDF. Hier voor wordt gebruik gemaakt van de ‘formatDate’ functie. Binnen de 2e parameter kun je opgeven in welk formaat de datum weergegeven moet worden. Je kunt hiervoor kiezen uit de volgende PHP class constanten uit de Mage_Core_Model_Locale class:

  • Mage_Core_Model_Locale::FORMAT_TYPE_FULL = ‘full’
  • Mage_Core_Model_Locale::FORMAT_TYPE_LONG = ‘long’
  • Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM = ‘medium’
  • Mage_Core_Model_Locale::FORMAT_TYPE_SHORT = ‘short’

Als je werkt met de Nederlandse Magento dan kun je de volgende output verwachten:

  • ‘full’ = maandag 31 januari 2011
  • ‘long’ = 31 januari 2011
  • ‘medium’ = 31 jan. 2011
  • ‘short’ = 31-01-11

Met de 3e parameter kun je overigens opgeven of je de tijd ook wilt weergeven. Als je hier false opgeeft zal de tijd niet worden weergeven, bij true wel.

Categorieën
Geen categorie

Tolsma’s dart toernooi 2010

Elke jaar op de een na laatste dag van het jaar wordt het Tolsma’s dart toernooi georganiseerd. Dit jaar zal de 5e editie van dit altijd erg gezellige toernooi plaats vinden. Vorig jaar werd er al flink wat ge’tweet over het Tolsma’s dart toernooi. Om die reden zal er dit jaar een Twitterfountain aanwezig zijn.

Categorieën
PHP WordPress

Gravity Forms custom posts

Via Gravity Form is het mogelijk om je bezoekers (concept)berichten te laten plaatsen. Je kunt hierbij gebruik maken van verschillende vooraf gedefinieerde velden. Helaas is het nog niet mogelijk om custom posts aan te maken. Gelukkig is deze functionaliteit met behulp van filters en hooks wel te realiseren.

function custom_gform_set_post_type($post_data, $form) {
	$classes = explode(' ', $form['cssClass']);

	$items = apply_filters('custom_gform_post_type_classes', array());

	foreach($items as $class => $post_type) {
		if(in_array($class, $classes)) {
			$post_data['post_type'] = $post_type;
		}
	}

    return $post_data;
}

add_filter('gform_post_data', 'custom_gform_set_post_type', 10, 2);

Vervolgens kun je met behulp van de volgende filter CSS classes koppelen aan een custom post type.

function dvt_gform_post_type_classes($ptc) {
	$ptc['opponent-form'] = 'opponent';

	return $ptc;
}

add_filter('custom_gform_post_type_classes', 'dvt_gform_post_type_classes');
Categorieën
PHP WordPress

Gravity Forms custom taxonomies dropdown

Via Gravity Form is het mogelijk om je bezoekers (concept)berichten te laten plaatsen. Je kunt hierbij gebruik maken van verschillende vooraf gedefinieerde velden. Helaas is er nog geen standaard veld beschikbaar voor custom post types en taxonomies. Gelukkig is deze functionaliteit met behulp van filters en hooks wel te realiseren.

Populate dropdown

function custom_gform_dropdown_terms($arguments, $withEmpty = true) {
	$terms = get_terms($arguments);

	$items = array();

	if($withEmpty) {
		$items[] = array('text' => '', 'value' => '');
	}

	foreach($terms as $term) {
		$items[] = array('value' => $term->term_id, 'text' => $term->name);
	}

	return $items;
}

function custom_gform_populate_dropdown($form) {
	$items = apply_filters('custom_gform_taxonomies_classes', array());

	foreach($form['fields'] as &$field) {
		$classes = explode(' ', $field['cssClass']);

		foreach($items as $class => $taxonomy) {
			if(in_array($class, $classes)) {
				$field['type'] = 'select';
				$field['choices'] = custom_gform_dropdown_terms($taxonomy);
			}
		}
	}

	return $form;
}

add_filter('gform_pre_render', 'custom_gform_populate_dropdown');

Koppel CSS class met taxonomy

Vervolgens kun je met behulp van de volgende filter CSS classes koppelen aan een taxonomy.

function dvt_gform_taxonomy_classes($tc) {
	$tc['taxonomy-level'] = 'level';
	$tc['taxonomy-region'] = 'region';

	return $tc;
}

add_filter('custom_gform_taxonomies_classes', 'dvt_gform_taxonomy_classes');

Terms opslaan per post

Tot slot zorgt het volgende code fragment er voor dat de terms worden opgeslagen bij de betreffende post.

function custom_gform_save_terms($lead, $form) {
	// Check if the submission contains a WordPress post
	if(isset($lead['post_id'])) {
		$items = apply_filters('custom_gform_taxonomies_classes', array());

		foreach($form['fields'] as &$field) {
			$classes = explode(' ', $field['cssClass']);

			foreach($items as $class => $taxonomy) {
				if(in_array($class, $classes)) {
					$value = (int) $lead[$field['id']];

					wp_set_object_terms($lead['post_id'], $value, $taxonomy);
				}
			}
		}
	}
}

add_action('gform_post_submission', 'custom_gform_save_terms', 10, 2);

Bronnen

Categorieën
Magento PHP

Magento webwinkel verhuizen

Het verhuizen van een Magento webwinkel naar een nieuwe server / locatie kan een hele klus zijn. Een Magento installatie die al een aantal jaren actief kan al snel 2+ GB aan ruimte in nemen. Met meer dan 100.000+ bestanden en 25.000+ mappen kan het verhuizen veel tijd kosten. Daarnaast is er vaak ook een MySQL database die 500+ MB aan data bevat.

Op de Wiki van Magento staat beschreven hoe je een Magento installatie kunt verhuizen naar een andere locatie. In eerste instantie wordt beschreven dat je een nieuwe Magento installatie moet opzetten en vervolgens de oude data moet importeren. Aan het eind van het artikel wordt echter ook een alternatieve methode toegelicht. In de alternatieve variant hoef je geen nieuwe Magento installatie opzetten. In plaats daarvan moet je daadwerkelijk alle bestanden en de database naar de nieuwe locatie verplaatsen.

Er zijn wel een aantal aandachtspunten waar je rekening mee moeten houden als je een Magento webwinkel op deze manier gaat verhuizen. Zo zul je in veel gevallen het bestand pear.ini (downloader/pearlib/pear.ini) moeten wijzigen om de MagentoConnect manager te laten werken.

Magento heeft hier een eenvoudig script voor beschikbaar gesteld die een nieuw pear.ini bestand voor je kan generen. Ik zelf vond het Magento script niet heel gebruiksvriendelijk en heb daarom een aantal verbeteringen aangebracht.

<?php

define('CR', "\r");
define('LF', "\n");
define('CRLF', CR . LF);

$contents = explode(LF, file_get_contents('pear.ini'));

$data = unserialize($contents[1]);

if(isset($data['bin_dir'])) {
	$oldPath = $data['bin_dir'];
	$newPath = getcwd();

	foreach($data as $key => $value) {
		if(is_string($value)) {
			$data[$key] = str_replace($oldPath, $newPath, $value);
		}
	}
}

?>
<!DOCTYPE html>

<html lang="en">
	<head>
		<meta charset="utf-8" />

		<title>Magento pear.ini generator | Pronamic</title>
	</head>

	<body>
		<h1>Magento pear.ini generator</h1>

		<h2>Paths</h2>

		<dl>
			<dt>Old path</dt>
			<dd>
				<?php if(isset($oldPath)): ?>
				<code><?php echo $oldPath; ?></code>
				<?php else: ?>
				<em>Unknown</em>
				<?php endif; ?>
			</dd>

			<dt>New path</dt>
			<dd>
				<?php if(isset($newPath)): ?>
				<code><?php echo $newPath; ?></code>
				<?php else: ?>
				<em>Unknown</em>
				<?php endif; ?>
			</dd>
		</dl>

		<h2>pear.ini</h2>

		<?php 

		$pearIni = $contents[0] . LF . serialize($data);

		?>
		<p>
			<textarea name="pear.ini" cols="80" rows="10"><?php echo $pearIni; ?></textarea>
		</p>
	</body>
</html>

Mocht je ooit een Mangeto webwinkel moeten verhuizen dan kan dit script zeker van pas komen!

Categorieën
JavaScript jQuery PHP WordPress

WordPress GEO afstand

Op de website van Pronamic is in de voettekst een leuke GEO functionaliteit opgenomen:

In dit bericht zal ik beschrijven hoe je deze functionaliteit kunt toevoegen aan je eigen WordPress website. Allereerst voegen we aan footer.php de volgende code toe:

<div id="location-footer" class="geolocation">
	<?php get_template_part('geo', 'location-footer'); ?>
</div>

Vervolgens maken we binnen de theme map het bestand geo-location-footer.php aan. Binnen dit bestand plaatsen we de volgende code:

<?php

global $distanceToHQ;

if(isset($distanceToHQ) && $distanceToHQ < 50): ?>

Volgens GeoIP bent u minder dan 50 km verwijderd van een kopje koffie en een goed gesprek over internet. Kom vrijblijvend eens <a href="/contact/">bij ons langs</a>. Volgt u ons trouwens al op <a href="http://www.twitter.com/pronamic">Twitter</a>?

<?php else: ?>

Wij komen graag eens bij u langs voor een goed gesprek. Neem vrijblijvend <a href="/contact/">contact</a> met ons op. Volg ons op <a href="http://www.twitter.com/pronamic">Twitter</a>.
Bekijk onze foto's op <a href="http://www.flickr.com/groups/pronamic/">FlickR</a> of wordt lid van onze groep op <a href="http://pronamic.hyves.nl/">Hyves</a>.

<?php endif; ?>

Vervolgens voegen we de volgende code toe aan functions.php.

/**
 * Calculate distance between to points and return it in the specified unit
 */
function rt_calculate_distance($lat1, $lon1, $lat2, $lon2, $unit) {
	$theta = $lon1 - $lon2; 

	$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
	$dist = acos($dist);
	$dist = rad2deg($dist); 

	$miles = $dist * 60 * 1.1515;

	$unit = strtoupper($unit);

	if($unit == 'K') {
		return ($miles * 1.609344);
	} else if($unit == 'N') {
		return ($miles * 0.8684);
	} else {
		return $miles;
	}
}

/**
 * Calculate distance between to points and return it in the specified unit
 */
function rt_distance($location1, $location2, $unit) {
	return rt_calculate_distance($location1->latitude, $location1->longitude, $location2->latitude, $location2->longitude, $unit);
}

////////////////////////////////////////////////////////////

/**
 * AJAX
 */
function rt_ajax_geo() {
	$hqLocation = new stdClass();
	$hqLocation->latitude = 53.056079;
	$hqLocation->longitude = 6.200763;

	$clientLocation = new stdClass();
	$clientLocation->latitude = (float) filter_input(INPUT_POST, 'latitude', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
	$clientLocation->longitude = (float) filter_input(INPUT_POST, 'longitude', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);

	global $distanceToHQ;

	$distanceToHQ = rt_distance($hqLocation, $clientLocation, 'K');

	$element = filter_input(INPUT_POST, 'element', FILTER_SANITIZE_STRING);

	get_template_part('geo', $element);

	die();
}

add_action('wp_ajax_rt_geo', 'rt_ajax_geo');
add_action('wp_ajax_nopriv_rt_geo', 'rt_ajax_geo');

////////////////////////////////////////////////////////////

function rt_geo_scripts() {
	$key = 'INSERT-YOUR-KEY';

	wp_register_script('google-jsapi',
		'https://www.google.com/jsapi?key=' . $key
	);

	wp_register_script('rt-geo-script',
		get_bloginfo('template_directory') . '/js/geo.js' ,
		array('google-jsapi', 'jquery') ,
		'1.0'
	);

	wp_enqueue_script('rt-geo-script');
}

add_action('template_redirect', 'rt_geo_scripts');

Je moet voor het gebruik van deze functionaliteit een Google JS API key aanvragen. Vervang de tekst INSERT-YOUR-KEY in bovenstaande code met je eigen API key.

De laatste stap is om binnen je theme map het JavaScript bestand geo.js aan te maken in de map js met de volgende inhoud:

jQuery(document).ready(function($) {
	if($.isPlainObject(google.loader.ClientLocation)) {
		var clientLocation = google.loader.ClientLocation;

		$(".geolocation").each(function() {
			var element = $(this);

			var data = {
				action: "rt_geo" ,
				element: element.attr("id") ,
				latitude: clientLocation.latitude ,
				longitude: clientLocation.longitude
			};

			$.post("/wp-admin/admin-ajax.php", data, function(response) {
				element.html(response);
			});
		});
	}
});

Als het goed is zou je nu een dynamisch blok in je footer moeten hebben die geüpdate wordt zodra de afstand tussen de bezoeker en je locatie bekend is. Je kunt uiteraard geo-location-footer.php helemaal naar je eigen wens aanpassen. Daarnaast kun je een onbeperkt aantal GEO elementen toevoegen. Mocht je vragen, opmerkingen, verbeteringen, etc. hebben laat dan even een reactie achter!

Categorieën
WordPress

WordPress Shopp plugin vertalingen (nl_NL)

Voor een opdracht bij Pronamic hebben we gebruik gemaakt van de WordPress Shopp plugin. Deze plugin tovert elke WordPress installatie om naar een eenvoudige webwinkel.
De plugin is ontwikkeld door Ingenesis Limited (weblog) een bedrijf uit Springfield (Ohio, Verenigde Staten).

De plugin is standaard alleen in het Engels beschikbaar. Gelukkig kan de plugin dankzij het WordPress vertaalmechanisme eenvoudige worden vertaald. Hiranthi
van Illutic WebDesign uit Enschede heeft al een Nederlandse vertaling op de Shopp website geplaatst.

Helaas was deze vertaling ietwat gedateerd en ontbrak het .PO bestand.
Gelukkig kunnen .MO bestanden eenvoudig omgezet worden naar .PO bestanden.
Als je gebruik maakt van Poedit kun je hiervoor
het volgende commando gebruiken:

C:\Program Files\Poedit\bin
msgunfmt Shopp-nl_NL.mo > Shopp-nl_NL.po

Vervolgens kun je binnen Poedit dit .PO bestand bijwerken naar het
recentste .POT bestand van de Shopp plugin.

Voor het gemak heb ik de .PO en .MO bestanden online gezet:

Helaas zijn de vertalingen nog niet volledig en up-to-date:

67% vertaald, 1256 teksten (216 onzeker, 0 ongeldige symbolen, 188 niet vertaald

Categorieën
Linux PHP

OpenSSL fout Twinfield API

Een aantal weken terug wilde ik bij Pronamic wat experimenteren met de Twinfield API. De Twinfield API werkt met behulp van SOAP over een beveiligde HTTP verbinding. Volgens Twinfield zou je op de volgende manier een verbinding moeten kunnen maken:

$soapClient = new SoapClient('https://login.twinfield.com/webservices/session.asmx?wsdl', array('trace' => 1));

Helaas resulteerde het uitvoeren van bovenstaande PHP code in een foutmelding:

Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:14092073:SSL routines:SSL3_GET_SERVER_HELLO:bad packet length in Twinfield.php on line 8

Call Stack:
    0.0002     651112   1. {main}() Twinfield.php:0
    0.0003     651896   2. file_get_contents() Twinfield.php:8

Warning: file_get_contents(): Failed to enable crypto in Twinfield.php on line 8

Call Stack:
    0.0002     651112   1. {main}() Twinfield.php:0
    0.0003     651896   2. file_get_contents() Twinfield.php:8

Warning: file_get_contents(https://login.twinfield.com/webservices/session.asmx?wsdl): failed to open stream: operation failed in Twinfield.php on line 8

Call Stack:
    0.0002     651112   1. {main}() Twinfield.php:0
    0.0003     651896   2. file_get_contents() Twinfield.php:8

Fatal error: SoapClient::SoapClient(): 'uri' option is required in nonWSDL mode in Twinfield.php on line 13

Call Stack:
    0.0002     651112   1. {main}() Twinfield.php:0
    0.0686     653888   2. SoapClient->SoapClient() Twinfield.php:13

Dezelfde code werkte echter wel op een andere server, maar helaas niet op mijn ontwikkel- en test server. Dat was toch wel erg vervelend, daarom ben ik opzoek gegaan naar een oplossing. Ik kwam na een speurtocht al snel anderen tegen met vergelijkbare problemen. Zo rapporteerde [email protected] een vergelijkbare fout in PHP’s bug tracking systeem.

Ik kon echter erg lastig een oplossing vinden voor het probleem. Ik las wel op verschillende websites dat het om een probleem in het OpenSSL pakket ging. Op mijn Debian ontwikkel- en test server had ik OpenSSL/0.9.8g geïnstalleerd. Dit is momenteel de stabiele versie van het OpenSSL pakket op het debian platform. Aangezien ik geen concrete oplossing kon vinden voor het probleem heb ik de test versie van OpenSSL geïnstalleerd.

Hiervoor heb ik eerst de volgende regels toegevoegd aan /etc/apt/sources.list.

deb http://ftp.nl.debian.org/debian squeeze main
deb-src http://ftp.nl.debian.org/debian/ squeeze main

Vervolgens heb ik OpenSSL en Apache opnieuw geïnstalleerd met behulp van de volgende commando’s:

# apt-get install openssl

# apt-get install apache

Sindsdien heb ik OpenSSL/0.9.8o draaien op mijn server en is mijn probleem opgelost. Ik kan nu zonder problemen de Twinfield SOAP API aanroepen.